aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml41
-rw-r--r--CONTRIBUTING.md56
-rw-r--r--COPYRIGHT40
-rw-r--r--HCAR-Pandoc.tex2
-rw-r--r--INSTALL29
-rw-r--r--Makefile36
-rw-r--r--README699
-rw-r--r--RELEASE-CHECKLIST4
-rw-r--r--Setup.hs68
-rw-r--r--appveyor.yml21
-rw-r--r--benchmark/benchmark-pandoc.hs19
-rw-r--r--changelog1151
-rw-r--r--data/docx/[Content_Types].xml2
-rw-r--r--data/docx/_rels/.rels2
-rw-r--r--data/docx/docProps/app.xml18
-rw-r--r--data/docx/docProps/core.xml2
-rw-r--r--data/docx/word/_rels/document.xml.rels2
-rw-r--r--data/docx/word/_rels/footnotes.xml.rels2
-rw-r--r--data/docx/word/document.xml2
-rw-r--r--data/docx/word/fontTable.xml52
-rw-r--r--data/docx/word/footnotes.xml26
-rw-r--r--data/docx/word/numbering.xml2
-rw-r--r--data/docx/word/settings.xml47
-rw-r--r--data/docx/word/styles.xml396
-rw-r--r--data/docx/word/theme/theme1.xml2
-rw-r--r--data/docx/word/webSettings.xml5
-rw-r--r--data/dzslides/template.html158
-rw-r--r--data/epub.css1
-rw-r--r--data/make-reference-files.hs27
-rw-r--r--data/odt/Configurations2/accelerator/current.xml0
-rw-r--r--data/odt/META-INF/manifest.xml12
-rw-r--r--data/odt/Thumbnails/thumbnail.pngbin0 -> 785 bytes
-rw-r--r--data/odt/content.xml2
-rw-r--r--data/odt/manifest.rdf18
-rw-r--r--data/odt/meta.xml18
-rw-r--r--data/odt/mimetype1
-rw-r--r--data/odt/settings.xml2
-rw-r--r--data/odt/styles.xml1096
-rw-r--r--data/reference.docxbin8619 -> 0 bytes
-rw-r--r--data/reference.odtbin10890 -> 0 bytes
m---------data/templates13
-rw-r--r--deb/control.in20
-rwxr-xr-xmake_deb.sh63
-rwxr-xr-xmake_osx_package.sh7
-rw-r--r--man/capitalizeHeaders.hs20
-rw-r--r--man/make-pandoc-man-pages.hs104
-rw-r--r--man/man1/pandoc.1.template16
-rw-r--r--man/man5/pandoc_markdown.5.template11
-rw-r--r--man/pandoc.14336
-rw-r--r--man/pandoc.1.template10
-rw-r--r--man/removeLinks.hs9
-rw-r--r--man/removeNotes.hs9
-rw-r--r--pandoc.cabal195
-rw-r--r--pandoc.hs101
-rw-r--r--relann1.6170
-rw-r--r--src/Text/Pandoc.hs67
-rw-r--r--src/Text/Pandoc/Asciify.hs4
-rw-r--r--src/Text/Pandoc/Compat/Locale.hs9
-rw-r--r--src/Text/Pandoc/Data.hsb2
-rw-r--r--src/Text/Pandoc/Error.hs64
-rw-r--r--src/Text/Pandoc/Highlighting.hs4
-rw-r--r--src/Text/Pandoc/ImageSize.hs196
-rw-r--r--src/Text/Pandoc/MIME.hs11
-rw-r--r--src/Text/Pandoc/MediaBag.hs6
-rw-r--r--src/Text/Pandoc/Options.hs58
-rw-r--r--src/Text/Pandoc/PDF.hs56
-rw-r--r--src/Text/Pandoc/Parsing.hs97
-rw-r--r--src/Text/Pandoc/Pretty.hs27
-rw-r--r--src/Text/Pandoc/Process.hs4
-rw-r--r--src/Text/Pandoc/Readers/CommonMark.hs119
-rw-r--r--src/Text/Pandoc/Readers/DocBook.hs116
-rw-r--r--src/Text/Pandoc/Readers/Docx.hs64
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs256
-rw-r--r--src/Text/Pandoc/Readers/Docx/StyleMap.hs106
-rw-r--r--src/Text/Pandoc/Readers/Docx/Util.hs26
-rw-r--r--src/Text/Pandoc/Readers/EPUB.hs37
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs124
-rw-r--r--src/Text/Pandoc/Readers/Haddock.hs12
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs335
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs219
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs24
-rw-r--r--src/Text/Pandoc/Readers/Native.hs44
-rw-r--r--src/Text/Pandoc/Readers/OPML.hs48
-rw-r--r--src/Text/Pandoc/Readers/Odt.hs86
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/State.hs253
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs497
-rw-r--r--src/Text/Pandoc/Readers/Odt/Base.hs43
-rw-r--r--src/Text/Pandoc/Readers/Odt/ContentReader.hs790
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs260
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs62
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs48
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Utils.hs171
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs1064
-rw-r--r--src/Text/Pandoc/Readers/Odt/Namespaces.hs110
-rw-r--r--src/Text/Pandoc/Readers/Odt/StyleReader.hs737
-rw-r--r--src/Text/Pandoc/Readers/Org.hs257
-rw-r--r--src/Text/Pandoc/Readers/RST.hs150
-rw-r--r--src/Text/Pandoc/Readers/TWiki.hs527
-rw-r--r--src/Text/Pandoc/Readers/TeXMath.hs4
-rw-r--r--src/Text/Pandoc/Readers/Textile.hs41
-rw-r--r--src/Text/Pandoc/Readers/Txt2Tags.hs8
-rw-r--r--src/Text/Pandoc/SelfContained.hs107
-rw-r--r--src/Text/Pandoc/Shared.hs140
-rw-r--r--src/Text/Pandoc/Slides.hs4
-rw-r--r--src/Text/Pandoc/Templates.hs9
-rw-r--r--src/Text/Pandoc/UTF8.hs14
-rw-r--r--src/Text/Pandoc/UUID.hs4
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs10
-rw-r--r--src/Text/Pandoc/Writers/CommonMark.hs178
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs23
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs146
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs15
-rw-r--r--src/Text/Pandoc/Writers/Docx.hs420
-rw-r--r--src/Text/Pandoc/Writers/DokuWiki.hs30
-rw-r--r--src/Text/Pandoc/Writers/EPUB.hs243
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs2
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs205
-rw-r--r--src/Text/Pandoc/Writers/ICML.hs29
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs106
-rw-r--r--src/Text/Pandoc/Writers/Man.hs4
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs152
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs12
-rw-r--r--src/Text/Pandoc/Writers/Native.hs4
-rw-r--r--src/Text/Pandoc/Writers/ODT.hs38
-rw-r--r--src/Text/Pandoc/Writers/OPML.hs7
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs17
-rw-r--r--src/Text/Pandoc/Writers/Org.hs4
-rw-r--r--src/Text/Pandoc/Writers/RST.hs84
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs17
-rw-r--r--src/Text/Pandoc/Writers/Shared.hs4
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs16
-rw-r--r--src/Text/Pandoc/Writers/Textile.hs6
-rw-r--r--src/Text/Pandoc/XML.hs4
-rw-r--r--tests/Tests/Old.hs8
-rw-r--r--tests/Tests/Readers/Docx.hs29
-rw-r--r--tests/Tests/Readers/EPUB.hs10
-rw-r--r--tests/Tests/Readers/HTML.hs27
-rw-r--r--tests/Tests/Readers/LaTeX.hs52
-rw-r--r--tests/Tests/Readers/Markdown.hs163
-rw-r--r--tests/Tests/Readers/Odt.hs165
-rw-r--r--tests/Tests/Readers/Org.hs150
-rw-r--r--tests/Tests/Readers/RST.hs103
-rw-r--r--tests/Tests/Readers/Txt2Tags.hs3
-rw-r--r--tests/Tests/Writers/Docx.hs129
-rw-r--r--tests/Tests/Writers/LaTeX.hs6
-rw-r--r--tests/Tests/Writers/Markdown.hs91
-rw-r--r--tests/Tests/Writers/RST.hs79
-rw-r--r--tests/docbook-reader.docbook44
-rw-r--r--tests/docbook-reader.native74
-rw-r--r--tests/docx/danish_headers.docxbin17691 -> 0 bytes
-rw-r--r--tests/docx/danish_headers.native10
-rw-r--r--tests/docx/german_styled_lists.docxbin0 -> 43957 bytes
-rw-r--r--tests/docx/german_styled_lists.native6
-rw-r--r--tests/docx/headers.docxbin30298 -> 29659 bytes
-rw-r--r--tests/docx/headers.native10
-rw-r--r--tests/docx/i18n_blocks.docxbin0 -> 13680 bytes
-rw-r--r--tests/docx/i18n_blocks.native8
-rw-r--r--tests/docx/image_no_embed_writer.native2
-rw-r--r--tests/docx/image_vml.docxbin0 -> 23559 bytes
-rw-r--r--tests/docx/image_vml.native4
-rw-r--r--tests/docx/inline_formatting_writer.native5
-rw-r--r--tests/docx/inline_images_writer.native2
-rw-r--r--tests/docx/links.docxbin41751 -> 45115 bytes
-rw-r--r--tests/docx/links.native1
-rw-r--r--tests/docx/links_writer.native6
-rw-r--r--tests/docx/lists_writer.native17
-rw-r--r--tests/docx/table_with_list_cell.docxbin0 -> 32615 bytes
-rw-r--r--tests/docx/table_with_list_cell.native11
-rw-r--r--tests/docx/verbatim_subsuper.docxbin0 -> 10353 bytes
-rw-r--r--tests/docx/verbatim_subsuper.native8
-rw-r--r--tests/dokuwiki_external_images.dokuwiki1
-rw-r--r--tests/dokuwiki_external_images.native1
-rw-r--r--tests/dokuwiki_inline_formatting.dokuwiki3
-rw-r--r--tests/html-reader.html252
-rw-r--r--tests/html-reader.native129
-rw-r--r--tests/latex-reader.latex27
-rw-r--r--tests/latex-reader.native11
-rw-r--r--tests/lhs-test.html46
-rw-r--r--tests/lhs-test.html+lhs46
-rw-r--r--tests/lhs-test.latex66
-rw-r--r--tests/lhs-test.latex+lhs17
-rw-r--r--tests/markdown-reader-more.native13
-rw-r--r--tests/markdown-reader-more.txt22
-rw-r--r--tests/media/rId25.jpg0
-rw-r--r--tests/media/rId26.jpg0
-rw-r--r--tests/media/rId27.jpg0
-rw-r--r--tests/mediawiki-reader.native2
-rw-r--r--tests/mediawiki-reader.wiki2
-rw-r--r--tests/odt/markdown/bold.md1
-rw-r--r--tests/odt/markdown/citation.md1
-rw-r--r--tests/odt/markdown/endnote.md3
-rw-r--r--tests/odt/markdown/externalLink.md1
-rw-r--r--tests/odt/markdown/footnote.md3
-rw-r--r--tests/odt/markdown/headers.md9
-rw-r--r--tests/odt/markdown/horizontalRule.md1
-rw-r--r--tests/odt/markdown/image.md1
-rw-r--r--tests/odt/markdown/imageIndex.md6
-rw-r--r--tests/odt/markdown/imageWithCaption.md1
-rw-r--r--tests/odt/markdown/italic.md1
-rw-r--r--tests/odt/markdown/listBlocks.md6
-rw-r--r--tests/odt/markdown/paragraph.md5
-rw-r--r--tests/odt/markdown/strikeout.md1
-rw-r--r--tests/odt/markdown/trackedChanges.md1
-rw-r--r--tests/odt/markdown/underlined.md1
-rw-r--r--tests/odt/native/blockquote.native1
-rw-r--r--tests/odt/native/orderedListMixed.native1
-rw-r--r--tests/odt/native/orderedListRoman.native1
-rw-r--r--tests/odt/native/orderedListSimple.native1
-rw-r--r--tests/odt/native/referenceToChapter.native1
-rw-r--r--tests/odt/native/referenceToListItem.native1
-rw-r--r--tests/odt/native/referenceToText.native1
-rw-r--r--tests/odt/native/simpleTable.native1
-rw-r--r--tests/odt/native/unicode.native1
-rw-r--r--tests/odt/native/unorderedList.native1
-rw-r--r--tests/odt/odt/blockquote.odtbin0 -> 8594 bytes
-rw-r--r--tests/odt/odt/bold.odtbin0 -> 10377 bytes
-rw-r--r--tests/odt/odt/citation.odtbin0 -> 10842 bytes
-rw-r--r--tests/odt/odt/endnote.odtbin0 -> 10950 bytes
-rw-r--r--tests/odt/odt/expression.odtbin0 -> 10916 bytes
-rw-r--r--tests/odt/odt/expressionUnevaluated.odtbin0 -> 10829 bytes
-rw-r--r--tests/odt/odt/externalLink.odtbin0 -> 10735 bytes
-rw-r--r--tests/odt/odt/footnote.odtbin0 -> 10843 bytes
-rw-r--r--tests/odt/odt/formula.odtbin0 -> 14252 bytes
-rw-r--r--tests/odt/odt/headers.odtbin0 -> 10515 bytes
-rw-r--r--tests/odt/odt/hiddenTextByStyle.odtbin0 -> 10798 bytes
-rw-r--r--tests/odt/odt/hiddenTextByVariable.odtbin0 -> 10788 bytes
-rw-r--r--tests/odt/odt/horizontalRule.odtbin0 -> 10130 bytes
-rw-r--r--tests/odt/odt/image.odtbin0 -> 33360 bytes
-rw-r--r--tests/odt/odt/imageIndex.odtbin0 -> 34417 bytes
-rw-r--r--tests/odt/odt/imageWithCaption.odtbin0 -> 33811 bytes
-rw-r--r--tests/odt/odt/italic.odtbin0 -> 10426 bytes
-rw-r--r--tests/odt/odt/listBlocks.odtbin0 -> 10565 bytes
-rw-r--r--tests/odt/odt/orderedListMixed.odtbin0 -> 10580 bytes
-rw-r--r--tests/odt/odt/orderedListRoman.odtbin0 -> 10622 bytes
-rw-r--r--tests/odt/odt/orderedListSimple.odtbin0 -> 10570 bytes
-rw-r--r--tests/odt/odt/paragraph.odtbin0 -> 8538 bytes
-rw-r--r--tests/odt/odt/referenceAllInOne.odtbin0 -> 10878 bytes
-rw-r--r--tests/odt/odt/referenceToChapter.odtbin0 -> 10487 bytes
-rw-r--r--tests/odt/odt/referenceToListItem.odtbin0 -> 10855 bytes
-rw-r--r--tests/odt/odt/referenceToText.odtbin0 -> 10179 bytes
-rw-r--r--tests/odt/odt/simpleTable.odtbin0 -> 10705 bytes
-rw-r--r--tests/odt/odt/strikeout.odtbin0 -> 10582 bytes
-rw-r--r--tests/odt/odt/table.odtbin0 -> 10763 bytes
-rw-r--r--tests/odt/odt/tableWithCaption.odtbin0 -> 10623 bytes
-rw-r--r--tests/odt/odt/trackedChanges.odtbin0 -> 11135 bytes
-rw-r--r--tests/odt/odt/underlined.odtbin0 -> 10513 bytes
-rw-r--r--tests/odt/odt/unicode.odtbin0 -> 11787 bytes
-rw-r--r--tests/odt/odt/unorderedList.odtbin0 -> 9505 bytes
-rw-r--r--tests/odt/odt/variable.odtbin0 -> 10851 bytes
-rw-r--r--tests/pipe-tables.txt4
-rw-r--r--tests/rst-reader.native6
-rw-r--r--tests/s5-basic.html2
-rw-r--r--tests/s5-fragment.html2
-rw-r--r--tests/s5-inserts.html2
-rw-r--r--tests/tables.asciidoc1
-rw-r--r--tests/tables.haddock1
-rw-r--r--tests/tables.opendocument8
-rw-r--r--tests/tables.org1
-rw-r--r--tests/tables.rst1
-rw-r--r--tests/test-pandoc.hs8
-rw-r--r--tests/twiki-reader.native174
-rw-r--r--tests/twiki-reader.twiki221
-rw-r--r--tests/writer.asciidoc7
-rw-r--r--tests/writer.context2
-rw-r--r--tests/writer.dokuwiki74
-rw-r--r--tests/writer.fb22
-rw-r--r--tests/writer.html22
-rw-r--r--tests/writer.icml173
-rw-r--r--tests/writer.latex108
-rw-r--r--tests/writer.markdown26
-rw-r--r--tests/writer.mediawiki7
-rw-r--r--tests/writer.opendocument5
-rw-r--r--tests/writer.opml18
-rw-r--r--tests/writer.plain10
-rw-r--r--tests/writer.rst7
-rw-r--r--tests/writer.texinfo46
-rw-r--r--tests/writer.textile16
-rw-r--r--trypandoc/index.html28
-rw-r--r--trypandoc/trypandoc.hs7
-rw-r--r--windows/make-windows-installer.bat2
-rw-r--r--windows/pandoc.wxs341
282 files changed, 18961 insertions, 2728 deletions
diff --git a/.gitignore b/.gitignore
index 97150be15..c3154ea10 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,3 +20,5 @@ man/man?/*.html
/windows/*.msi
/windows/*.wixpdb
windows/*.wixobj
+data/reference.docx
+data/reference.odt
diff --git a/.travis.yml b/.travis.yml
index 1ca7a1228..9a67ac32b 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,28 +1,39 @@
# NB: don't set `language: haskell` here
+# Ensures that sudo is disabled, so that containerized builds are allowed
+sudo: false
+
# The following enables several GHC versions to be tested; often it's enough to test only against the last release in a major GHC version. Feel free to omit lines listings versions you don't need/want testing for.
-env:
-# - GHCVER=6.12.3
- - GHCVER=7.4.2
- - GHCVER=7.6.3
- - GHCVER=7.8.2 # see note about Alex/Happy
-# - GHCVER=head # see section about GHC HEAD snapshots
+matrix:
+ include:
+ - env: CABALVER=1.16 GHCVER=7.4.2 GHCOPTS="-Werror" JOPTS=""
+ addons: {apt: {packages: [cabal-install-1.16, ghc-7.4.2], sources: [hvr-ghc]}}
+ - env: CABALVER=1.18 GHCVER=7.6.3 GHCOPTS="-Werror" JOPTS="-j2"
+ addons: {apt: {packages: [cabal-install-1.18, ghc-7.6.3], sources: [hvr-ghc]}}
+ - env: CABALVER=1.18 GHCVER=7.8.4 GHCOPTS="-Werror" JOPTS="-j2"
+ addons: {apt: {packages: [cabal-install-1.18, ghc-7.8.4], sources: [hvr-ghc]}}
+ - env: CABALVER=1.22 GHCVER=7.10.1 GHCOPTS="" JOPTS="-j2"
+ addons: {apt: {packages: [cabal-install-1.22, ghc-7.10.1],sources: [hvr-ghc]}}
+# - env: CABALVER=head GHCVER=head GHCOPTS="-Werror" JOPTS="-j2"
+# addons: {apt: {packages: [cabal-install-head,ghc-head], sources: [hvr-ghc]}}
# Note: the distinction between `before_install` and `install` is not important.
before_install:
- - travis_retry sudo add-apt-repository -y ppa:hvr/ghc
- - travis_retry sudo apt-get update
- - travis_retry sudo apt-get install cabal-install-1.18 ghc-$GHCVER
- export PATH=/opt/ghc/$GHCVER/bin:$PATH
install:
- - cabal-1.18 update
+ - cabal-$CABALVER update
# - git clone https://github.com/jgm/pandoc-types && cd pandoc-types && cabal-1.18 install && cd ..
- - cabal-1.18 install --only-dependencies --enable-tests
+ - cabal-$CABALVER install $JOPTS --only-dependencies --enable-tests
# Here starts the actual work to be performed for the package under test; any command which exits with a non-zero exit code causes the build to fail.
script:
- - cabal-1.18 configure --enable-tests -v2 # -v2 provides useful information for debugging
- - cabal-1.18 build --ghc-options=-Werror # this builds all libraries and executables (including tests/benchmarks)
- - cabal-1.18 test
- - cabal-1.18 check
+ - |
+ if [ "${CABALVER}" != "1.16" ]; then
+ cabal-$CABALVER sdist --output-directory=build
+ cd build
+ fi
+ - cabal-$CABALVER configure --enable-tests -v2 # -v2 provides useful information for debugging
+ - cabal-$CABALVER build $JOPTS --ghc-options=$GHCOPTS # this builds all libraries and executables (including tests/benchmarks)
+ - cabal-$CABALVER test
+ - cabal-$CABALVER check
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 824d1465e..7b321f868 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -25,6 +25,32 @@ including
A small test case (just a few lines) is ideal. If your input is large,
try to whittle it down to the minimum necessary to illustrate the problem.
+Fixing bugs from the issue tracker
+----------------------------------
+
+Almost all the bugs on the issue tracker have one or more associated
+tags. These are used to indicate the *difficulty* and *nature* of a
+bug. There is not yet a way to indicate priority. An up to date
+summary of issues can be found [here](https://github.com/jgm/pandoc/labels).
+
+* [enhancement] -- A feature which would be desirable. We recommend
+ you discuss any proposed enhancement on pandoc-discuss before
+ writing code.
+* [bug] -- A problem which needs to be fixed.
+* [minor] -- The fix should only be a couple of lines.
+* [major] -- The fix might require structural changes or in depth knowledge of
+the code base.
+* [reader] -- A request to add a new input format.
+* [writer] -- A request to add a new output format.
+* [docs] -- A discrepency or ambiguity in the documentation.
+* [inprogress] -- Someone is actively working on or planning to work on the
+ ticket.
+* [more discussion needed] -- It is unclear what the correct approach
+ to solving the ticket is. Before starting on tickets such as this it
+ would be advisable to post on the ticket.
+* [more info needed] -- We require more information from a user before
+ we can classify a report properly.
+
Have an idea for a new feature?
-------------------------------
@@ -94,6 +120,20 @@ The test program is `tests/test-pandoc.hs`.
Benchmarks can be enabled by passing the `--enable-benchmarks` flag
to `cabal configure`, and run using `cabal bench`.
+Using the REPL
+--------------
+
+With a recent version of cabal, you can do `cabal repl` and get
+a ghci REPL for working with pandoc. We recommend using the following
+`.ghci` file (which can be placed in the source directory):
+
+```
+:set -fobject-code
+:set -XTypeSynonymInstances
+:set -XScopedTypeVariables
+:set -XOverloadedStrings
+```
+
The code
--------
@@ -122,7 +162,7 @@ the pandoc library is in `src/`, the source for the tests is in
`tests/`, and the source for the benchmarks is in `benchmark/`.
The modules `Text.Pandoc.Definition`, `Text.Pandoc.Builder`, and
-`Text.Pandoc.Generics` are in a separate library `pandoc-types`. The code can
+`Text.Pandoc.Generic` are in a separate library `pandoc-types`. The code can
be found in a <http://github.com/jgm/pandoc-types>.
To build pandoc, you will need a working installation of the
@@ -177,8 +217,18 @@ The library is structured as follows:
[pandoc-discuss]: http://groups.google.com/group/pandoc-discuss
[issue tracker]: https://github.com/jgm/pandoc/issues
-[User's Guide]: http://johnmacfarlane.net/pandoc/README.html
-[FAQs]: http://johnmacfarlane.net/pandoc/faqs.html
+[User's Guide]: http://pandoc.org/README.html
+[FAQs]: http://pandoc.org/faqs.html
[EditorConfig]: http://editorconfig.org/
[Haskell platform]: http://www.haskell.org/platform/
[hsb2hs]: http://hackage.haskell.org/package/hsb2hs
+[enhancement]: https://github.com/jgm/pandoc/labels/enhancement
+[bug]: https://github.com/jgm/pandoc/labels/bug
+[minor]: https://github.com/jgm/pandoc/labels/Minor
+[major]: https://github.com/jgm/pandoc/labels/Major
+[reader]: https://github.com/jgm/pandoc/labels/Reader
+[writer]: https://github.com/jgm/pandoc/labels/Writer
+[docs]: https://github.com/jgm/pandoc/labels/docs
+[inprogress]: https://github.com/jgm/pandoc/labels/inprogress
+[more discussion needed]: https://github.com/jgm/pandoc/labels/More%20discussion%20needed
+[more info needed]: https://github.com/jgm/pandoc/labels/More%20info%20needed
diff --git a/COPYRIGHT b/COPYRIGHT
index 065090018..19b532129 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -1,5 +1,5 @@
Pandoc
-Copyright (C) 2006-2014 John MacFarlane <jgm at berkeley dot edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm at berkeley dot edu>
This code is released under the [GPL], version 2 or later:
@@ -25,7 +25,7 @@ GPL can be found in `/usr/share/common-licenses/GPL`.
Pandoc's complete source code is available from the [Pandoc home page].
-[Pandoc home page]: http://johnmacfarlane.net/pandoc/
+[Pandoc home page]: http://pandoc.org
Pandoc includes some code from other authors. The copyright and license
statements for these sources are included below. All are GPL-compatible
@@ -33,32 +33,32 @@ licenses.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/Texinfo.hs
-Copyright (C) 2008-2014 John MacFarlane and Peter Wang
+Copyright (C) 2008-2015 John MacFarlane and Peter Wang
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/OpenDocument.hs
-Copyright (C) 2008-2014 Andrea Rossato and John MacFarlane
+Copyright (C) 2008-2015 Andrea Rossato and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Writers/Org.hs
-Copyright (C) 2010-2014 Puneeth Chaganti and JohnMacFarlane
+Copyright (C) 2010-2015 Puneeth Chaganti and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Textile.hs
-Copyright (C) 2010-2014 Paul Rivier and John MacFarlane
+Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Org.hs
tests/Tests/Readers/Org.hs
-Copyright (C) 2014 Albert Krewinkel
+Copyright (C) 2014-2015 Albert Krewinkel
Released under the GNU General Public License version 2 or later.
@@ -79,6 +79,30 @@ Released under the GNU General Public License version 2 or later.
------------------------------------------------------------------------
The dzslides template contains javascript and CSS from Paul Rouget's
dzslides template.
-http://github.com/apulrouget/dzslides
+http://github.com/paulrouget/dzslides
Released under the Do What the Fuck You Want To Public License.
+
+------------------------------------------------------------------------
+Pandoc embeds a lua interpreter (via hslua).
+
+Copyright © 1994–2015 Lua.org, PUC-Rio.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/HCAR-Pandoc.tex b/HCAR-Pandoc.tex
index 5b6a4d56f..a91ca0b25 100644
--- a/HCAR-Pandoc.tex
+++ b/HCAR-Pandoc.tex
@@ -31,5 +31,5 @@ These last two changes bring two of the most powerful features of \LaTeX
to pandoc.
\FurtherReading
- \url{http://johnmacfarlane.net/pandoc/}
+ \url{http://pandoc.org}
\end{hcarentry}
diff --git a/INSTALL b/INSTALL
index eb9b2b030..4f20c9d67 100644
--- a/INSTALL
+++ b/INSTALL
@@ -24,6 +24,15 @@ Quick install
This procedure will install the released version of pandoc,
which will be downloaded automatically from HackageDB.
+
+ If this step fails, and you are using an older version
+ of the Haskell Platform, e.g. on Debian stable, you may need to
+ upgrade your version of cabal:
+
+ cabal install cabal-install
+ ~/.cabal/bin/cabal update
+ ~/.cabal/bin/cabal install pandoc
+
If you want to install a modified or development version
of pandoc instead, switch to the source directory and do
as above, but without the 'pandoc':
@@ -44,12 +53,7 @@ Quick install
[Not sure where `$CABALDIR` is?](http://www.haskell.org/haskellwiki/Cabal-Install#The_cabal-install_configuration_file)
-5. Make sure the `$CABALDIR/share/man/man1` directory is in your `MANPATH`.
- You should now be able to access the `pandoc` man page:
-
- man pandoc
-
-6. If you want to process citations with pandoc, you will also need to
+5. If you want to process citations with pandoc, you will also need to
install a separate package, `pandoc-citeproc`. This can be installed
using cabal:
@@ -71,6 +75,13 @@ Quick install
--extra-include-dirs=/usr/local/Cellar/icu4c/51.1/include \
-funicode_collation text-icu pandoc-citeproc
+The `pandoc.1` man page will be installed automatically. cabal shows
+you where it is installed: you may need to set your `MANPATH`
+accordingly. If `README` has been modified, the man page can be
+rebuilt: `make man/pandoc.1`.
+
+The `pandoc-citeproc.1` man page will also be installed automatically.
+
[GHC]: http://www.haskell.org/ghc/
[Haskell platform]: http://hackage.haskell.org/platform/
[cabal-install]: http://hackage.haskell.org/trac/hackage/wiki/CabalInstall
@@ -108,9 +119,8 @@ assume that the pandoc source directory is your working directory.
- `embed_data_files`: embed all data files into the binary (default no).
This is helpful if you want to create a relocatable binary.
Note: if this option is selected, you need to install the
- `hsb2hs` preprocessor:
-
- cabal install hsb2hs
+ `hsb2hs` preprocessor: `cabal install hsb2hs` (version 0.3.1 or
+ higher is required).
- `https`: enable support for downloading resources over https
(using the `http-client` and `http-client-tls` libraries).
@@ -200,4 +210,3 @@ To use a smaller sample size so the benchmarks run faster:
To run just the markdown benchmarks:
cabal bench --benchmark-options='markdown'
-
diff --git a/Makefile b/Makefile
index 589130b72..a44085420 100644
--- a/Makefile
+++ b/Makefile
@@ -1,22 +1,17 @@
version=$(shell grep '^Version:' pandoc.cabal | awk '{print $$2;}')
-makemanpages=$(shell find dist -type f -name make-pandoc-man-pages)
-ifeq "${makemanpages}" ""
- makemanpages=@echo "You need to 'cabal configure -fmake-pandoc-man-pages && cabal build'" && exit 1
-endif
-setup=dist/setup/setup
-MANPAGES=man/man1/pandoc.1 man/man5/pandoc_markdown.5
+pandoc=$(shell find dist -name pandoc -type f -exec ls -t {} \; | head -1)
quick:
- cabal configure --enable-tests --disable-optimization
+ cabal --ignore-sandbox configure --enable-tests -fembed_data_files --disable-optimization
cabal build
full:
- cabal configure --enable-tests --enable-optimization -ftrypandoc -fmake-pandoc-man-pages -fembed_data_files --enable-benchmarks
+ cabal configure --enable-tests --enable-optimization -ftrypandoc -fembed_data_files --enable-benchmarks
cabal build
cabal haddock
deps:
- cabal install --only-dependencies --enable-tests -ftrypandoc -fmake-pandoc-man-pages -fembed_data_files --enable-benchmarks
+ cabal install --only-dependencies --enable-tests -ftrypandoc -fembed_data_files --enable-benchmarks
prof:
cabal configure --enable-library-profiling --enable-executable-profiling --enable-optimization --enable-tests
@@ -32,26 +27,31 @@ install: full
cabal copy
cabal register
-dist: man
+dist: man/pandoc.1
cabal sdist
rm -rf "pandoc-${version}"
tar xvzf dist/pandoc-${version}.tar.gz
cd pandoc-${version}
cabal configure ${CABALARGS} && cabal build && cabal test && cd .. && rm -rf "pandoc-${version}"
-man: ${MANPAGES}
+debpkg: man/pandoc.1
+ ./make_deb.sh
-osxpkg:
+osxpkg: man/pandoc.1
./make_osx_package.sh
-%.1: %.1.template README
- ${makemanpages}
+man/pandoc.1: README man/pandoc.1.template
+ pandoc $< -t man -s --template man/pandoc.1.template \
+ --filter man/capitalizeHeaders.hs \
+ --filter man/removeNotes.hs \
+ --filter man/removeLinks.hs \
+ -o $@
-%.5: %.5.template README
- ${makemanpages}
+download_stats:
+ curl https://api.github.com/repos/jgm/pandoc/releases | \
+ jq -r '.[] | .assets | .[] | "\(.download_count)\t\(.name)"'
clean:
cabal clean
- -rm ${MANPAGES}
-.PHONY: deps quick full install man clean test bench haddock osxpkg dist prof
+.PHONY: deps quick full install clean test bench osxpkg dist prof download_stats
diff --git a/README b/README
index d2fcd51f1..38b8a588e 100644
--- a/README
+++ b/README
@@ -1,27 +1,29 @@
% Pandoc User's Guide
% John MacFarlane
-% August 30, 2014
+% July 15, 2015
Synopsis
========
-pandoc [*options*] [*input-file*]...
+`pandoc` [*options*] [*input-file*]...
Description
===========
Pandoc is a [Haskell] library for converting from one markup format to
another, and a command-line tool that uses this library. It can read
-[markdown] and (subsets of) [Textile], [reStructuredText], [HTML],
-[LaTeX], [MediaWiki markup], [Haddock markup], [OPML], [Emacs
-Org-mode], [DocBook], [txt2tags], [EPUB] and [Word docx]; and it can write plain text,
-[markdown], [reStructuredText], [XHTML], [HTML 5], [LaTeX] (including
+[Markdown], [CommonMark], and (subsets of) [Textile],
+[reStructuredText], [HTML], [LaTeX], [MediaWiki markup], [TWiki
+markup], [Haddock markup], [OPML], [Emacs Org-mode], [DocBook],
+[txt2tags], [EPUB], [ODT] and [Word docx]; and it can write plain text,
+[Markdown], [reStructuredText], [XHTML], [HTML 5], [LaTeX] (including
[beamer] slide shows), [ConTeXt], [RTF], [OPML], [DocBook],
[OpenDocument], [ODT], [Word docx], [GNU Texinfo], [MediaWiki markup],
-[DokuWiki markup], [Haddock markup], [EPUB] (v2 or v3), [FictionBook2],
-[Textile], [groff man] pages, [Emacs Org-Mode], [AsciiDoc], [InDesign ICML],
-and [Slidy], [Slideous], [DZSlides], [reveal.js] or [S5] HTML slide shows.
-It can also produce [PDF] output on systems where LaTeX is installed.
+[DokuWiki markup], [Haddock markup], [EPUB] (v2 or v3),
+[FictionBook2], [Textile], [groff man] pages, [Emacs Org-Mode],
+[AsciiDoc], [InDesign ICML], and [Slidy], [Slideous], [DZSlides],
+[reveal.js] or [S5] HTML slide shows. It can also produce [PDF] output
+on systems where LaTeX is installed.
Pandoc's enhanced version of markdown includes syntax for footnotes,
tables, flexible ordered lists, definition lists, fenced code blocks,
@@ -50,6 +52,15 @@ default (though output to *stdout* is disabled for the `odt`, `docx`,
pandoc -o output.html input.txt
+By default, pandoc produces a document fragment, not a standalone
+document with a proper header and footer. To produce a standalone
+document, use the `-s` or `--standalone` flag:
+
+ pandoc -s -o output.html input.txt
+
+For more information on how standalone documents are produced, see
+[Templates](#templates), below.
+
Instead of a file, an absolute URI may be given. In this case
pandoc will fetch the content using HTTP:
@@ -57,7 +68,7 @@ pandoc will fetch the content using HTTP:
If multiple input files are given, `pandoc` will concatenate them all (with
blank lines between them) before parsing. This feature is disabled for
- binary input formats such as `EPUB` and `docx`.
+ binary input formats such as `EPUB`, `odt`, and `docx`.
The format of the input and output can be specified explicitly using
command-line options. The input format can be specified using the
@@ -95,6 +106,11 @@ should pipe input and output through `iconv`:
iconv -t utf-8 input.txt | pandoc | iconv -f utf-8
+Note that in some output formats (such as HTML, LaTeX, ConTeXt,
+RTF, OPML, DocBook, and Texinfo), information about
+the character encoding is included in the document header, which
+will only be included if you use the `-s/--standalone` option.
+
Creating a PDF
--------------
@@ -111,7 +127,8 @@ Production of a PDF requires that a LaTeX engine be installed (see
`--latex-engine`, below), and assumes that the following LaTeX packages are
available: `amssymb`, `amsmath`, `ifxetex`, `ifluatex`, `listings` (if the
`--listings` option is used), `fancyvrb`, `longtable`, `booktabs`, `url`,
-`graphicx`, `hyperref`, `ulem`, `babel` (if the `lang` variable is set),
+`graphicx` and `grffile` (if the document contains images),
+ `hyperref`, `ulem`, `babel` (if the `lang` variable is set),
`fontspec` (if `xelatex` or `lualatex` is used as the LaTeX engine), `xltxtra`
and `xunicode` (if `xelatex` is used).
@@ -139,62 +156,70 @@ General options
---------------
`-f` *FORMAT*, `-r` *FORMAT*, `--from=`*FORMAT*, `--read=`*FORMAT*
+
: Specify input format. *FORMAT* can be `native` (native Haskell),
`json` (JSON version of native AST), `markdown` (pandoc's
- extended markdown), `markdown_strict` (original unextended markdown),
- `markdown_phpextra` (PHP Markdown Extra extended markdown),
- `markdown_github` (github extended markdown),
- `textile` (Textile), `rst` (reStructuredText), `html` (HTML),
- `docbook` (DocBook), `t2t` (txt2tags), `docx` (docx), `epub` (EPUB),
- `opml` (OPML), `org` (Emacs Org-mode), `mediawiki` (MediaWiki markup),
- `haddock` (Haddock markup), or `latex` (LaTeX). If `+lhs` is appended
- to `markdown`, `rst`,
- `latex`, or `html`, the input will be treated as literate Haskell
- source: see [Literate Haskell support](#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
+ extended markdown), `markdown_strict` (original unextended
+ markdown), `markdown_phpextra` (PHP Markdown Extra extended
+ markdown), `markdown_github` (github extended markdown),
+ `commonmark` (CommonMark markdown), `textile` (Textile), `rst`
+ (reStructuredText), `html` (HTML), `docbook` (DocBook), `t2t`
+ (txt2tags), `docx` (docx), `odt` (ODT), `epub` (EPUB), `opml` (OPML),
+ `org` (Emacs Org-mode), `mediawiki` (MediaWiki markup), `twiki` (TWiki
+ markup), `haddock` (Haddock markup), or `latex` (LaTeX). If
+ `+lhs` is appended to `markdown`, `rst`, `latex`, or `html`, the
+ input will be treated as literate Haskell source: see [Literate
+ Haskell support](#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](#pandocs-markdown), below, for a list of extensions and
their names.
`-t` *FORMAT*, `-w` *FORMAT*, `--to=`*FORMAT*, `--write=`*FORMAT*
+
: Specify output format. *FORMAT* can be `native` (native Haskell),
`json` (JSON version of native AST), `plain` (plain text),
- `markdown` (pandoc's extended markdown), `markdown_strict` (original
- unextended markdown), `markdown_phpextra` (PHP Markdown extra
- extended markdown), `markdown_github` (github extended markdown),
- `rst` (reStructuredText), `html` (XHTML 1), `html5` (HTML 5),
- `latex` (LaTeX), `beamer` (LaTeX beamer slide show),
- `context` (ConTeXt), `man` (groff man), `mediawiki` (MediaWiki markup),
- `dokuwiki` (DokuWiki markup),
- `textile` (Textile), `org` (Emacs Org-Mode), `texinfo` (GNU Texinfo),
- `opml` (OPML), `docbook` (DocBook), `opendocument` (OpenDocument), `odt`
- (OpenOffice text document), `docx` (Word docx), `haddock` (Haddock
- markup), `rtf` (rich text format), `epub` (EPUB v2 book), `epub3`
- (EPUB v3), `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc),
- `icml` (InDesign ICML), `slidy` (Slidy HTML and javascript slide show),
- `slideous` (Slideous HTML and javascript slide show), `dzslides`
- (DZSlides HTML5 + javascript slide show), `revealjs` (reveal.js
- HTML5 + javascript slide show), `s5` (S5 HTML and javascript slide show),
- or the path of a custom lua writer (see [Custom writers](#custom-writers),
- below). 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`,
- `html`, or `html5`, the output will be rendered as literate Haskell
- source: see [Literate Haskell support](#literate-haskell-support), below.
- Markdown syntax extensions can be individually enabled or disabled by
- appending `+EXTENSION` or `-EXTENSION` to the format name, as described
+ `markdown` (pandoc's extended markdown), `markdown_strict`
+ (original unextended markdown), `markdown_phpextra` (PHP Markdown
+ extra extended markdown), `markdown_github` (github extended
+ markdown), `commonmark` (CommonMark markdown), `rst`
+ (reStructuredText), `html` (XHTML 1), `html5` (HTML 5), `latex`
+ (LaTeX), `beamer` (LaTeX beamer slide show), `context` (ConTeXt),
+ `man` (groff man), `mediawiki` (MediaWiki markup), `dokuwiki`
+ (DokuWiki markup), `textile` (Textile), `org` (Emacs Org-Mode),
+ `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` (DocBook),
+ `opendocument` (OpenDocument), `odt` (OpenOffice text document),
+ `docx` (Word docx), `haddock` (Haddock markup), `rtf` (rich text
+ format), `epub` (EPUB v2 book), `epub3` (EPUB v3), `fb2`
+ (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml` (InDesign
+ ICML), `slidy` (Slidy HTML and javascript slide show), `slideous`
+ (Slideous HTML and javascript slide show), `dzslides` (DZSlides
+ HTML5 + javascript slide show), `revealjs` (reveal.js HTML5 +
+ javascript slide show), `s5` (S5 HTML and javascript slide show),
+ or the path of a custom lua writer (see [Custom
+ writers](#custom-writers), below). 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`,
+ `html`, or `html5`, the output will be rendered as literate
+ Haskell source: see [Literate Haskell
+ support](#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`.
`-o` *FILE*, `--output=`*FILE*
+
: Write output to *FILE* instead of *stdout*. If *FILE* is
`-`, output will go to *stdout*. (Exception: if the output
format is `odt`, `docx`, `epub`, or `epub3`, output to stdout is disabled.)
`--data-dir=`*DIRECTORY*
+
: Specify the user data directory to search for pandoc data files.
If this option is not specified, the default user data directory
will be used. This is
@@ -215,16 +240,24 @@ General options
`epub.css`, `templates`, `slidy`, `slideous`, or `s5` directory
placed in this directory will override pandoc's normal defaults.
+`--verbose`
+
+: Give verbose debugging output. Currently this only has an effect
+ with PDF output.
+
`-v`, `--version`
+
: Print version.
`-h`, `--help`
+
: Show usage message.
Reader options
--------------
`-R`, `--parse-raw`
+
: Parse untranslatable HTML codes and LaTeX environments as raw HTML
or LaTeX, instead of ignoring them. Affects only HTML and LaTeX
input. Raw HTML can be printed in markdown, reStructuredText, HTML,
@@ -235,35 +268,41 @@ Reader options
LaTeX *commands*, even if `-R` is not specified.)
`-S`, `--smart`
+
: Produce typographically correct output, converting straight quotes
to curly quotes, `---` to em-dashes, `--` to en-dashes, and
`...` to ellipses. Nonbreaking spaces are inserted after certain
abbreviations, such as "Mr." (Note: This option is significant only when
- the input format is `markdown`, `markdown_strict`, or `textile`. It
- is selected automatically when the input format is `textile` or the
+ the input format is `markdown`, `markdown_strict`, `textile` or `twiki`.
+ It is selected automatically when the input format is `textile` or the
output format is `latex` or `context`, unless `--no-tex-ligatures`
is used.)
`--old-dashes`
+
: Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes: `-` before
a numeral is an en-dash, and `--` is an em-dash. This option is selected
automatically for `textile` input.
`--base-header-level=`*NUMBER*
+
: Specify the base level for headers (defaults to 1).
`--indented-code-classes=`*CLASSES*
+
: Specify classes to use for indented code blocks--for example,
`perl,numberLines` or `haskell`. Multiple classes may be separated
by spaces or commas.
`--default-image-extension=`*EXTENSION*
+
: Specify a default extension to use when image paths/URLs have no
extension. This allows you to use the same source for formats that
require different kinds of images. Currently this option only affects
the markdown and LaTeX readers.
`--filter=`*EXECUTABLE*
+
: Specify an executable to be used as a filter transforming the
Pandoc AST after the input is parsed and before the output is
written. The executable should read JSON from stdin and write
@@ -284,12 +323,18 @@ Reader options
Those who would prefer to write filters in python can use the
module `pandocfilters`, installable from PyPI. See
<http://github.com/jgm/pandocfilters> for the module and several
- examples. Note that the *EXECUTABLE* will be sought in the user's
+ examples. There are also pandoc filter libraries in
+ [PHP](https://github.com/vinai/pandocfilters-php),
+ [perl](https://metacpan.org/pod/Pandoc::Filter), and
+ [javascript/node.js](https://github.com/mvhenderson/pandoc-filter-node).
+
+ Note that the *EXECUTABLE* will be sought in the user's
`PATH`, and not in the working directory, if no directory is
provided. If you want to run a script in the working directory,
preface the filename with `./`.
-`-M` *KEY[=VAL]*, `--metadata=`*KEY[:VAL]*
+`-M` *KEY*[`=`*VAL*], `--metadata=`*KEY*[`:`*VAL*]
+
: Set the metadata field *KEY* to the value *VAL*. A value specified
on the command line overrides a value specified in the document.
Values will be parsed as YAML boolean or string values. If no value is
@@ -300,29 +345,34 @@ Reader options
printed in some output formats).
`--normalize`
+
: Normalize the document after reading: merge adjacent
`Str` or `Emph` elements, for example, and remove repeated `Space`s.
`-p`, `--preserve-tabs`
+
: Preserve tabs instead of converting them to spaces (the default).
Note that this will only affect tabs in literal code spans and code
blocks; tabs in regular text will be treated as spaces.
`--tab-stop=`*NUMBER*
+
: Specify the number of spaces per tab (default is 4).
-`--track-changes=`*accept|reject|all*
+`--track-changes=accept`|`reject`|`all`
+
: Specifies what to do with insertions and deletions produced by the MS
- Word "track-changes" feature. *accept* (the default), inserts all
- insertions, and ignores all deletions. *reject* inserts all
- deletions and ignores insertions. *all* puts in both insertions
+ Word "track-changes" feature. `accept` (the default), inserts all
+ insertions, and ignores all deletions. `reject` inserts all
+ deletions and ignores insertions. `all` puts in both insertions
and deletions, wrapped in spans with `insertion` and `deletion`
classes, respectively. The author and time of change is
- included. *all* is useful for scripting: only accepting changes
+ included. `all` is useful for scripting: only accepting changes
from a certain reviewer, say, or before a certain date. This
option only affects the docx reader.
`--extract-media=`*DIR*
+
: Extract images and other media contained in a docx or epub container
to the path *DIR*, creating it if necessary, and adjust the images
references in the document so they point to the extracted files.
@@ -332,23 +382,26 @@ General writer options
----------------------
`-s`, `--standalone`
+
: Produce output with an appropriate header and footer (e.g. a
standalone HTML, LaTeX, or RTF file, not a fragment). This option
is set automatically for `pdf`, `epub`, `epub3`, `fb2`, `docx`, and `odt`
output.
`--template=`*FILE*
+
: Use *FILE* as a custom template for the generated document. Implies
`--standalone`. See [Templates](#templates) below for a description
of template syntax. If no extension is specified, an extension
corresponding to the writer will be added, so that `--template=special`
looks for `special.html` for HTML output. If the template is not
- found, pandoc will search for it in the user data directory
- (see `--data-dir`). If this option is not used, a default
- template appropriate for the output format will be used (see
+ found, pandoc will search for it in the `templates` subdirectory of
+ the user data directory (see `--data-dir`). If this option is not used,
+ a default template appropriate for the output format will be used (see
`-D/--print-default-template`).
-`-V` *KEY[=VAL]*, `--variable=`*KEY[:VAL]*
+`-V` *KEY*[`=`*VAL*], `--variable=`*KEY*[`:`*VAL*]
+
: Set the template variable *KEY* to the value *VAL* when rendering the
document in standalone mode. This is generally only useful when the
`--template` option is used to specify a custom template, since
@@ -357,40 +410,52 @@ General writer options
value `true`.
`-D` *FORMAT*, `--print-default-template=`*FORMAT*
-: Print the default template for an output *FORMAT*. (See `-t`
- for a list of possible *FORMAT*s.)
+
+: Print the system default template for an output *FORMAT*. (See `-t`
+ for a list of possible *FORMAT*s.) Templates in the user data
+ directory are ignored.
`--print-default-data-file=`*FILE*
-: Print a default data file.
+
+: Print a system default data file. Files in the user data directory
+ are ignored.
`--no-wrap`
+
: Disable text wrapping in output. By default, text is wrapped
appropriately for the output format.
-`--columns`=*NUMBER*
+`--columns=`*NUMBER*
+
: Specify length of lines in characters (for text wrapping).
`--toc`, `--table-of-contents`
+
: Include an automatically generated table of contents (or, in
the case of `latex`, `context`, and `rst`, an instruction to create
one) in the output document. This option has no effect on `man`,
`docbook`, `slidy`, `slideous`, `s5`, `docx`, or `odt` output.
`--toc-depth=`*NUMBER*
+
: Specify the number of section levels to include in the table
of contents. The default is 3 (which means that level 1, 2, and 3
headers will be listed in the contents).
`--no-highlight`
+
: Disables syntax highlighting for code blocks and inlines, even when
a language attribute is given.
-`--highlight-style`=*STYLE*
+`--highlight-style=`*STYLE*
+
: Specifies the coloring style to be used in highlighted source code.
Options are `pygments` (the default), `kate`, `monochrome`,
- `espresso`, `zenburn`, `haddock`, and `tango`.
+ `espresso`, `zenburn`, `haddock`, and `tango`. For more information
+ on syntax highlighting in pandoc, see [Syntax highlighting], below.
`-H` *FILE*, `--include-in-header=`*FILE*
+
: Include contents of *FILE*, verbatim, at the end of the header.
This can be used, for example, to include special
CSS or javascript in HTML documents. This option can be used
@@ -398,6 +463,7 @@ General writer options
included in the order specified. Implies `--standalone`.
`-B` *FILE*, `--include-before-body=`*FILE*
+
: Include contents of *FILE*, verbatim, at the beginning of the
document body (e.g. after the `<body>` tag in HTML, or the
`\begin{document}` command in LaTeX). This can be used to include
@@ -406,6 +472,7 @@ General writer options
the order specified. Implies `--standalone`.
`-A` *FILE*, `--include-after-body=`*FILE*
+
: Include contents of *FILE*, verbatim, at the end of the document
body (before the `</body>` tag in HTML, or the
`\end{document}` command in LaTeX). This option can be be used
@@ -416,6 +483,7 @@ Options affecting specific writers
----------------------------------
`--self-contained`
+
: Produce a standalone HTML file with no external dependencies, using
`data:` URIs to incorporate the contents of linked scripts, stylesheets,
images, and videos. The resulting file should be "self-contained,"
@@ -429,41 +497,50 @@ Options affecting specific writers
file is remote). `--self-contained` does not work with `--mathjax`.
`--offline`
+
: Deprecated synonym for `--self-contained`.
`-5`, `--html5`
+
: Produce HTML5 instead of HTML4. This option has no effect for writers
other than `html`. (*Deprecated:* Use the `html5` output format instead.)
`--html-q-tags`
+
: Use `<q>` tags for quotes in HTML.
`--ascii`
+
: Use only ascii characters in output. Currently supported only
for HTML output (which uses numerical entities instead of
UTF-8 when this option is selected).
`--reference-links`
+
: Use reference-style links, rather than inline links, in writing markdown
or reStructuredText. By default inline links are used.
`--atx-headers`
+
: Use ATX style headers in markdown and asciidoc output. The default is
to use setext-style headers for levels 1-2, and then ATX headers.
`--chapters`
+
: Treat top-level headers as chapters in LaTeX, ConTeXt, and DocBook
output. When the LaTeX template uses the report, book, or
memoir class, this option is implied. If `beamer` is the output
format, top-level headers will become `\part{..}`.
`-N`, `--number-sections`
+
: Number section headings in LaTeX, ConTeXt, HTML, or EPUB output.
By default, sections are not numbered. Sections with class
`unnumbered` will never be numbered, even if `--number-sections`
is specified.
-`--number-offset`=*NUMBER[,NUMBER,...]*,
+`--number-offset=`*NUMBER*[`,`*NUMBER*`,`*...*]
+
: Offset for section headings in HTML output (ignored in other
output formats). The first number is added to the section number for
top-level headers, the second for second-level headers, and so on.
@@ -474,6 +551,7 @@ Options affecting specific writers
Offsets are 0 by default. Implies `--number-sections`.
`--no-tex-ligatures`
+
: Do not convert quotation marks, apostrophes, and dashes to
the TeX ligatures when writing LaTeX or ConTeXt. Instead, just
use literal unicode characters. This is needed for using advanced
@@ -485,13 +563,16 @@ Options affecting specific writers
without `--smart`.
`--listings`
+
: Use listings package for LaTeX code blocks
`-i`, `--incremental`
+
: Make list items in slide shows display incrementally (one by one).
The default is for lists to be displayed all at once.
-`--slide-level`=*NUMBER*
+`--slide-level=`*NUMBER*
+
: Specifies that headers with the specified level create
slides (for `beamer`, `s5`, `slidy`, `slideous`, `dzslides`). Headers
above this level in the hierarchy are used to divide the
@@ -501,34 +582,40 @@ Options affecting specific writers
[Structuring the slide show](#structuring-the-slide-show), below.
`--section-divs`
+
: Wrap sections in `<div>` tags (or `<section>` tags in HTML5),
and attach identifiers to the enclosing `<div>` (or `<section>`)
- rather than the header itself.
- See [Section identifiers](#header-identifiers-in-html-latex-and-context), below.
+ rather than the header itself. See
+ [Header identifiers](#header-identifiers), below.
+
+`--email-obfuscation=none`|`javascript`|`references`
-`--email-obfuscation=`*none|javascript|references*
: Specify a method for obfuscating `mailto:` links in HTML documents.
- *none* leaves `mailto:` links as they are. *javascript* obfuscates
- them using javascript. *references* obfuscates them by printing their
+ `none` leaves `mailto:` links as they are. `javascript` obfuscates
+ them using javascript. `references` obfuscates them by printing their
letters as decimal or hexadecimal character references.
-`--id-prefix`=*STRING*
+`--id-prefix=`*STRING*
+
: Specify a prefix to be added to all automatically generated identifiers
in HTML and DocBook output, and to footnote numbers in markdown output.
This is useful for preventing duplicate identifiers when generating
fragments to be included in other pages.
`-T` *STRING*, `--title-prefix=`*STRING*
+
: Specify *STRING* as a prefix at the beginning of the title
that appears in the HTML header (but not in the title as it
appears at the beginning of the HTML body). Implies
`--standalone`.
`-c` *URL*, `--css=`*URL*
+
: Link to a CSS style sheet. This option can be be used repeatedly to
include multiple files. They will be included in the order specified.
`--reference-odt=`*FILE*
+
: Use the specified file as a style reference in producing an ODT.
For best results, the reference ODT should be a modified version
of an ODT produced using pandoc. The contents of the reference ODT
@@ -539,6 +626,7 @@ Options affecting specific writers
used.
`--reference-docx=`*FILE*
+
: Use the specified file as a style reference in producing a docx file.
For best results, the reference docx should be a modified version
of a docx file produced using pandoc. The contents of the reference docx
@@ -548,25 +636,30 @@ Options affecting specific writers
for a file `reference.docx` in the user data directory (see
`--data-dir`). If this is not found either, sensible defaults will be
used. The following styles are used by pandoc: [paragraph]
- Normal, Compact, Title, Subtitle, Authors, Date, Abstract, Heading 1,
- Heading 2, Heading 3, Heading 4, Heading 5, Block Quote, Definition Term,
- Definition, Bibliography, Body Text, Table Caption, Image Caption;
+ Normal, Body Text, First Paragraph, Compact, Title, Subtitle, Author, Date,
+ Abstract, Bibliography, Heading 1, Heading 2, Heading 3, Heading 4,
+ Heading 5, Heading 6, Block Text, Footnote Text, Definition Term,
+ Definition, Caption, Table Caption, Image Caption, Figure,
+ Figure With Caption, TOC Heading;
[character] Default Paragraph Font, Body Text Char, Verbatim Char,
- Footnote Ref, Link.
+ Footnote Reference, Hyperlink; [table] Normal Table.
`--epub-stylesheet=`*FILE*
+
: Use the specified CSS file to style the EPUB. If no stylesheet
is specified, pandoc will look for a file `epub.css` in the
user data directory (see `--data-dir`). If it is not
found there, sensible defaults will be used.
`--epub-cover-image=`*FILE*
+
: Use the specified image as the EPUB cover. It is recommended
that the image be less than 1000px in width and height. Note that
in a markdown source document you can also specify `cover-image`
in a YAML metadata block (see [EPUB Metadata], below).
`--epub-metadata=`*FILE*
+
: Look in the specified XML file for metadata for the EPUB.
The file should contain a series of Dublin Core elements,
as documented at <http://dublincore.org/documents/dces/>.
@@ -588,10 +681,14 @@ Options affecting specific writers
[EPUB Metadata].
`--epub-embed-font=`*FILE*
+
: Embed the specified font in the EPUB. This option can be repeated
- to embed multiple fonts. To use embedded fonts, you
- will need to add declarations like the following to your CSS (see
- `--epub-stylesheet`):
+ to embed multiple fonts. Wildcards can also be used: for example,
+ `DejaVuSans-*.ttf`. However, if you use wildcards on the command
+ line, be sure to escape them or put the whole filename in single quotes,
+ to prevent them from being interpreted by the shell. To use the
+ embedded fonts, you will need to add declarations like the following
+ to your CSS (see `--epub-stylesheet`):
@font-face {
font-family: DejaVuSans;
@@ -620,6 +717,7 @@ Options affecting specific writers
body { font-family: "DejaVuSans"; }
`--epub-chapter-level=`*NUMBER*
+
: Specify the header level at which to split the EPUB into separate
"chapter" files. The default is to split into chapters at level 1
headers. This option only affects the internal composition of the
@@ -628,37 +726,55 @@ Options affecting specific writers
documents with few level 1 headers, one might want to use a chapter
level of 2 or 3.
-`--latex-engine=`*pdflatex|lualatex|xelatex*
+`--latex-engine=pdflatex`|`lualatex`|`xelatex`
+
: Use the specified LaTeX engine when producing PDF output.
The default is `pdflatex`. If the engine is not in your PATH,
the full path of the engine may be specified here.
+`--latex-engine-opt=`*STRING*
+
+: Use the given string as a command-line argument to the `latex-engine`.
+ If used multiple times, the arguments are provided with spaces between
+ them. Note that no check for duplicate options is done.
+
Citation rendering
------------------
`--bibliography=`*FILE*
+
: Set the `bibliography` field in the document's metadata to *FILE*,
overriding any value set in the metadata, and process citations
using `pandoc-citeproc`. (This is equivalent to
`--metadata bibliography=FILE --filter pandoc-citeproc`.)
+ If `--natbib` or `--biblatex` is also supplied, `pandoc-citeproc` is not
+ used, making this equivalent to `--metadata bibliography=FILE`.
+ If you supply this argument multiple times, each *FILE* will be added
+ to bibliography.
`--csl=`*FILE*
+
: Set the `csl` field in the document's metadata to *FILE*,
overriding any value set in the metadata. (This is equivalent to
`--metadata csl=FILE`.)
+ This option is only relevant with `pandoc-citeproc`.
`--citation-abbreviations=`*FILE*
+
: Set the `citation-abbreviations` field in the document's metadata to
*FILE*, overriding any value set in the metadata. (This is equivalent to
`--metadata citation-abbreviations=FILE`.)
+ This option is only relevant with `pandoc-citeproc`.
`--natbib`
+
: Use natbib for citations in LaTeX output. This option is not for use
with the `pandoc-citeproc` filter or with PDF output. It is intended for
use in producing a LaTeX file that can be processed with pdflatex and
bibtex.
`--biblatex`
+
: Use biblatex for citations in LaTeX output. This option is not for use
with the `pandoc-citeproc` filter or with PDF output. It is intended for
use in producing a LaTeX file that can be processed with pdflatex and
@@ -667,7 +783,8 @@ Citation rendering
Math rendering in HTML
----------------------
-`-m` [*URL*], `--latexmathml`[=*URL*]
+`-m` [*URL*], `--latexmathml`[`=`*URL*]
+
: Use the [LaTeXMathML] script to display embedded TeX math in HTML output.
To insert a link to a local copy of the `LaTeXMathML.js` script,
provide a *URL*. If no *URL* is provided, the contents of the
@@ -676,13 +793,15 @@ Math rendering in HTML
several pages, it is much better to link to a copy of the script,
so it can be cached.
-`--mathml`[=*URL*]
+`--mathml`[`=`*URL*]
+
: Convert TeX math to MathML (in `docbook` as well as `html` and `html5`).
In standalone `html` output, a small javascript (or a link to such a
script if a *URL* is supplied) will be inserted that allows the MathML to
be viewed on some browsers.
-`--jsmath`[=*URL*]
+`--jsmath`[`=`*URL*]
+
: Use [jsMath] to display embedded TeX math in HTML output.
The *URL* should point to the jsMath load script (e.g.
`jsMath/easy/load.js`); if provided, it will be linked to in
@@ -690,40 +809,47 @@ Math rendering in HTML
no link to the jsMath load script will be inserted; it is then
up to the author to provide such a link in the HTML template.
-`--mathjax`[=*URL*]
+`--mathjax`[`=`*URL*]
+
: Use [MathJax] to display embedded TeX math in HTML output.
The *URL* should point to the `MathJax.js` load script.
If a *URL* is not provided, a link to the MathJax CDN will
be inserted.
`--gladtex`
+
: Enclose TeX math in `<eq>` tags in HTML output. These can then
be processed by [gladTeX] to produce links to images of the typeset
formulas.
-`--mimetex`[=*URL*]
+`--mimetex`[`=`*URL*]
+
: Render TeX math using the [mimeTeX] CGI script. If *URL* is not
specified, it is assumed that the script is at `/cgi-bin/mimetex.cgi`.
-`--webtex`[=*URL*]
+`--webtex`[`=`*URL*]
+
: Render TeX formulas using an external script that converts TeX
formulas to images. The formula will be concatenated with the URL
provided. If *URL* is not specified, the Google Chart API will be used.
-`--katex`[=*URL*]
-: Use [KaTeX] to display embedded TeX math in HTML output.
- The *URL* should point to the `katex.js` load script. If a *URL* is
- not provided, a link to the KaTeX CDN will be inserted.
+`--katex`[`=`*URL*]
+
+: Use [KaTeX] to display embedded TeX math in HTML output.
+ The *URL* should point to the `katex.js` load script. If a *URL* is
+ not provided, a link to the KaTeX CDN will be inserted.
+
+`--katex-stylesheet=`*URL*
-`--katex-stylesheet=*URL*`
-: The *URL* should point to the `katex.css` stylesheet. If this option is
- not specified, a link to the KaTeX CDN will be inserted. Note that this
- option does not imply `--katex`.
+: The *URL* should point to the `katex.css` stylesheet. If this option is
+ not specified, a link to the KaTeX CDN will be inserted. Note that this
+ option does not imply `--katex`.
Options for wrapper scripts
---------------------------
`--dump-args`
+
: Print information about command-line arguments to *stdout*, then exit.
This option is intended primarily for use in wrapper scripts.
The first line of output contains the name of the output file specified
@@ -734,6 +860,7 @@ Options for wrapper scripts
after a `--` separator at the end of the line.
`--ignore-args`
+
: Ignore command-line arguments (for use in wrapper scripts).
Regular Pandoc options are not ignored. Thus, for example,
@@ -847,9 +974,10 @@ as `title`, `author`, and `date`) as well as the following:
`libertine` (Linux Libertine), `arev` (Arev Sans),
and the default `lmodern`, among others.
-`mainfont`, `sansfont`, `monofont`, `mathfont`
+`mainfont`, `sansfont`, `monofont`, `mathfont`, `CJKmainfont`
: fonts for LaTeX documents (works only with xelatex
- and lualatex)
+ and lualatex). Note that if `CJKmainfont` is used,
+ the `xeCJK` package must be available.
`colortheme`
: colortheme for LaTeX beamer documents
@@ -861,6 +989,9 @@ as `title`, `author`, and `date`) as well as the following:
: color for internal links in LaTeX documents (`red`, `green`,
`magenta`, `cyan`, `blue`, `black`)
+`toccolor`
+: color for links in table of contents in LaTeX documents
+
`urlcolor`
: color for external links in LaTeX documents
@@ -876,18 +1007,21 @@ as `title`, `author`, and `date`) as well as the following:
`toc-depth`
: level of section to include in table of contents in LaTeX documents
+`toc-title`
+: title of table of contents (works only with EPUB and docx)
+
`lof`
: include list of figures in LaTeX documents
`lot`
: include list of tables in LaTeX documents
+`bibliography`
+: bibliography to use for resolving references
+
`biblio-style`
: bibliography style in LaTeX, when used with `--natbib`
-`biblio-files`
-: bibliography files to use in LaTeX, with `--natbib` or `--biblatex`
-
`section`
: section number in man pages
@@ -976,7 +1110,7 @@ footnotes.
Paragraphs
----------
-A paragraph is one or more lines of text followed by one or more blank line.
+A paragraph is one or more lines of text followed by one or more blank lines.
Newlines are treated as spaces, so you can reflow your paragraphs as you like.
If you need a hard line break, put two or more spaces at the end of a line.
@@ -1033,7 +1167,7 @@ wrapping). Consider, for example:
#22, for example, and #5.
-### Header identifiers in HTML, LaTeX, and ConTeXt ###
+### Header identifiers ###
#### Extension: `header_attributes` ####
@@ -1143,10 +1277,17 @@ If there are multiple headers with identical text, the corresponding
reference will link to the first one only, and you will need to use explicit
links to link to the others, as described above.
-Unlike regular reference links, these references are case-sensitive.
+Like regular reference links, these references are case-insensitive.
+
+Explicit link reference definitions always take priority over
+implicit header references. So, in the following example, the
+link will point to `bar`, not to `#foo`:
-Note: if you have defined an explicit identifier for a header,
-then implicit references to it will not work.
+ # Foo
+
+ [foo]: bar
+
+ See [foo]
Block quotations
----------------
@@ -1217,9 +1358,9 @@ Note: blank lines in the verbatim text need not begin with four spaces.
In addition to standard indented code blocks, Pandoc supports
*fenced* code blocks. These begin with a row of three or more
-tildes (`~`) or backticks (`` ` ``) and end with a row of tildes or
-backticks that must be at least as long as the starting row. Everything
-between these lines is treated as code. No indentation is necessary:
+tildes (`~`) and end with a row of tildes that must be at least as long as
+the starting row. Everything between these lines is treated as code. No
+indentation is necessary:
~~~~~~~
if (a > 3) {
@@ -1239,9 +1380,14 @@ row of tildes or backticks at the start and end:
~~~~~~~~~~
~~~~~~~~~~~~~~~~
+#### Extension: `backtick_code_blocks` ####
+
+Same as `fenced_code_blocks`, but uses backticks (`` ` ``) instead of tildes
+(`~`).
+
#### Extension: `fenced_code_attributes` ####
-Optionally, you may attach attributes to the code block using
+Optionally, you may attach attributes to fenced or backtick code block using
this syntax:
~~~~ {#mycode .haskell .numberLines startFrom="100"}
@@ -1284,6 +1430,8 @@ word.
To prevent all highlighting, use the `--no-highlight` flag.
To set the highlighting style, use `--highlight-style`.
+For more information on highlighting, see [Syntax highlighting],
+below.
Line blocks
-----------
@@ -1800,8 +1948,8 @@ Pipe tables look like this:
The syntax is [the same as in PHP markdown extra]. The beginning and
ending pipe characters are optional, but pipes are required between all
columns. The colons indicate column alignment as shown. The header
-can be omitted, but the horizontal line must still be included, as
-it defines column alignments.
+cannot be omitted. To simulate a headerless table, include a header
+with blank cells.
Since the pipes indicate column boundaries, columns need not be vertically
aligned, as they are in the above example. So, this is a perfectly
@@ -1823,7 +1971,7 @@ to wrap within cells, use multiline or grid tables.
http://michelf.ca/projects/php-markdown/extra/#table
Note: Pandoc also recognizes pipe tables of the following
-form, as can produced by Emacs' orgtbl-mode:
+form, as can be produced by Emacs' orgtbl-mode:
| One | Two |
|-----+-------|
@@ -1938,6 +2086,11 @@ A document may contain multiple metadata blocks. The metadata fields will
be combined through a *left-biased union*: if two metadata blocks attempt
to set the same field, the value from the first block will be taken.
+When pandoc is used with `-t markdown` to create a markdown document,
+a YAML metadata block will be produced only if the `-s/--standalone`
+option is used. All of the metadata will appear in a single block
+at the beginning of the document.
+
Note that YAML escaping rules must be followed. Thus, for example,
if a title contains a colon, it must be quoted. The pipe character
(`|`) can be used to begin an indented block that will be interpreted
@@ -2146,7 +2299,7 @@ Markdown, LaTeX, Org-Mode, ConTeXt
reStructuredText
~ It will be rendered using an interpreted text role `:math:`, as described
- [here](http://www.american.edu/econ/itex2mml/mathhack.rst).
+ [here](http://docutils.sourceforge.net/docs/ref/rst/roles.html#math)
AsciiDoc
~ It will be rendered as `latexmath:[...]`.
@@ -2256,19 +2409,19 @@ by default, pandoc interprets material between HTML block tags as markdown.
Thus, for example, Pandoc will turn
<table>
- <tr>
- <td>*one*</td>
- <td>[a link](http://google.com)</td>
- </tr>
+ <tr>
+ <td>*one*</td>
+ <td>[a link](http://google.com)</td>
+ </tr>
</table>
into
<table>
- <tr>
- <td><em>one</em></td>
- <td><a href="http://google.com">a link</a></td>
- </tr>
+ <tr>
+ <td><em>one</em></td>
+ <td><a href="http://google.com">a link</a></td>
+ </tr>
</table>
whereas `Markdown.pl` will preserve it as is.
@@ -2365,6 +2518,10 @@ be followed by a link title, in quotes.)
There can be no space between the bracketed part and the parenthesized part.
The link text can contain formatting (such as emphasis), but the title cannot.
+Email addresses in inline links are not autodetected, so they have to be
+prefixed with `mailto`:
+
+ [Write me!](mailto:sam@green.eggs.ham)
### Reference links ###
@@ -2376,7 +2533,9 @@ The link consists of link text in square brackets, followed by a label in
square brackets. (There can be space between the two.) The link definition
consists of the bracketed label, followed by a colon and a space, followed by
the URL, and optionally (after a space) a link title either in quotes or in
-parentheses.
+parentheses. The label must not be parseable as a citation (assuming
+the `citations` extension is enabled): citations take precedence over
+link labels.
Here are some examples:
@@ -2401,9 +2560,9 @@ Note that link labels are not case sensitive. So, this will work:
[Foo]: /bar/baz
In an *implicit* reference link, the second pair of brackets is
-empty, or omitted entirely:
+empty:
- See [my website][], or [my website].
+ See [my website][].
[my website]: http://foo.bar.baz
@@ -2417,12 +2576,20 @@ not in most other implementations:
>
> [quote]: /foo
+#### Extension: `shortcut_reference_links` ####
+
+In a *shortcut* reference link, the second pair of brackets may
+be omitted entirely:
+
+ See [my website].
+
+ [my website]: http://foo.bar.baz
+
### Internal links ###
To link to another section of the same document, use the automatically
-generated identifier (see [Header identifiers in HTML, LaTeX, and
-ConTeXt](#header-identifiers-in-html-latex-and-context), below).
-For example:
+generated identifier (see [Header identifiers](#header-identifiers),
+below). For example:
See the [Introduction](#introduction).
@@ -2525,64 +2692,84 @@ citations and a bibliography in a number of styles. Basic usage is
pandoc --filter pandoc-citeproc myinput.txt
In order to use this feature, you will need to specify a bibliography file
-using the `bibliography` metadata field in a YAML metadata section.
+using the `bibliography` metadata field in a YAML metadata section, or
+`--bibliography` command line argument. You can supply multiple `--bibliography`
+arguments or set `bibliography` metadata field to YAML array, if you want to
+use multiple bibliography files.
The bibliography may have any of these formats:
Format File extension
------------ --------------
- MODS .mods
BibLaTeX .bib
BibTeX .bibtex
- RIS .ris
+ Copac .copac
+ CSL JSON .json
+ CSL YAML .yaml
EndNote .enl
EndNote XML .xml
ISI .wos
MEDLINE .medline
- Copac .copac
- JSON citeproc .json
+ MODS .mods
+ RIS .ris
Note that `.bib` can generally be used with both BibTeX and BibLaTeX
files, but you can use `.bibtex` to force BibTeX.
-Alternatively you can use a `references` field in the document's YAML
-metadata. This should include an array of YAML-encoded references,
-for example:
+Note that `pandoc-citeproc --bib2json` and `pandoc-citeproc --bib2yaml`
+can produce `.json` and `.yaml` files from any of the supported formats.
+
+In-field markup: In bibtex and biblatex databases, pandoc-citeproc parses
+(a subset of) LaTeX markup; in CSL JSON databases, an HTML-like markup
+([specs](http://docs.citationstyles.org/en/1.0/release-notes.html#rich-text-markup-within-fields));
+and in CSL YAML databases, pandoc markdown. `pandoc-citeproc -j` and `-y`
+interconvert these markup formats as far as possible.
+
+As an alternative to specifying a bibliography file, you can include
+the citation data directly in the `references` field of the
+document's YAML metadata. The field should contain an array of
+YAML-encoded references, for example:
---
references:
- - id: fenner2012a
- title: One-click science marketing
+ - type: article-journal
+ id: WatsonCrick1953
author:
- - family: Fenner
- given: Martin
- container-title: Nature Materials
- volume: 11
- URL: 'http://dx.doi.org/10.1038/nmat3283'
- DOI: 10.1038/nmat3283
- issue: 4
- publisher: Nature Publishing Group
- page: 261-263
- type: article-journal
+ - family: Watson
+ given: J. D.
+ - family: Crick
+ given: F. H. C.
issued:
- year: 2012
- month: 3
+ date-parts:
+ - - 1953
+ - 4
+ - 25
+ title: 'Molecular structure of nucleic acids: a structure for deoxyribose
+ nucleic acid'
+ title-short: Molecular structure of nucleic acids
+ container-title: Nature
+ volume: 171
+ issue: 4356
+ page: 737-738
+ DOI: 10.1038/171737a0
+ URL: http://www.nature.com/nature/journal/v171/n4356/abs/171737a0.html
+ language: en-GB
...
-(The program `mods2yaml`, which comes with `pandoc-citeproc`, can help produce
-these from a MODS reference collection.)
+(`pandoc-citeproc --bib2yaml` can produce these from a bibliography file in one
+of the supported formats.)
-By default, `pandoc-citeproc` will use a Chicago author-date format for
-citations and references. To use another style, you will need to specify
-a [CSL] 1.0 style file in the `csl` metadata field. A primer on creating and
+By default, `pandoc-citeproc` will use the Chicago Manual of Style author-date
+format for citations and references. To use another style, you will need to
+specify a [CSL] 1.0 style file in the `csl` metadata field. A repository of CSL
+styles can be found at <https://github.com/citation-style-language/styles>. See
+also <http://zotero.org/styles> for easy browsing. A primer on creating and
modifying CSL styles can be found at
-<http://citationstyles.org/downloads/primer.html>. A repository of CSL styles
-can be found at <https://github.com/citation-style-language/styles>. See also
-<http://zotero.org/styles> for easy browsing.
+<http://citationstyles.org/downloads/primer.html>.
Citations go inside square brackets and are separated by semicolons.
Each citation must have a key, composed of '@' + the citation
identifier from the database, and may optionally have a prefix,
-a locator, and a suffix. The citation key must begin with a letter
+a locator, and a suffix. The citation key must begin with a letter, digit,
or `_`, and may contain alphanumerics, `_`, and internal punctuation
characters (`:.#$%&-+?<>~/`). Here are some examples:
@@ -2631,6 +2818,12 @@ In this example, the document will contain a citation for `item3`
only, but the bibliography will contain entries for `item1`, `item2`, and
`item3`.
+For LaTeX or PDF output, you can also use NatBib or BibLaTeX
+to render bibliography. In order to do so, specify bibliography files as
+outlined above, and add `--natbib` or `--biblatex` argument to `pandoc`
+invocation. Bear in mind that bibliography files have to be in respective
+format (either BibTeX or BibLaTeX).
+
Non-pandoc extensions
---------------------
@@ -2760,20 +2953,22 @@ variants are supported:
`markdown_phpextra` (PHP Markdown Extra)
: `footnotes`, `pipe_tables`, `raw_html`, `markdown_attribute`,
`fenced_code_blocks`, `definition_lists`, `intraword_underscores`,
- `header_attributes`, `abbreviations`.
+ `header_attributes`, `abbreviations`, `shortcut_reference_links`.
-`markdown_github` (Github-flavored Markdown)
+`markdown_github` (GitHub-flavored Markdown)
: `pipe_tables`, `raw_html`, `tex_math_single_backslash`,
`fenced_code_blocks`, `auto_identifiers`,
`ascii_identifiers`, `backtick_code_blocks`, `autolink_bare_uris`,
- `intraword_underscores`, `strikeout`, `hard_line_breaks`
+ `intraword_underscores`, `strikeout`, `hard_line_breaks`,
+ `shortcut_reference_links`.
`markdown_mmd` (MultiMarkdown)
: `pipe_tables` `raw_html`, `markdown_attribute`, `link_attributes`,
`raw_tex`, `tex_math_double_backslash`, `intraword_underscores`,
`mmd_title_block`, `footnotes`, `definition_lists`,
`all_symbols_escapable`, `implicit_header_references`,
- `auto_identifiers`, `mmd_header_identifiers`
+ `auto_identifiers`, `mmd_header_identifiers`,
+ `shortcut_reference_links`.
`markdown_strict` (Markdown.pl)
: `raw_html`
@@ -2902,7 +3097,7 @@ you use deeper nesting of section levels with reveal.js.
Incremental lists
-----------------
-By default, these writers produces lists that display "all at once."
+By default, these writers produce lists that display "all at once."
If you want your lists to display incrementally (one item at a time),
use the `-i` option. If you want a particular list to depart from the
default (that is, to display incrementally without the `-i` option and
@@ -2982,6 +3177,16 @@ To show the notes window, press `s` while viewing the presentation.
Notes are not yet supported for other slide formats, but the notes
will not appear on the slides themselves.
+Marking frames "fragile" in beamer
+----------------------------------
+
+Sometimes it is necessary to add the LaTeX `[fragile]` option to
+a frame in beamer (for example, when using the `minted` environment).
+This can be forced by adding the `fragile` class to the header
+introducing the slide:
+
+ # Fragile slide {.fragile}
+
EPUB Metadata
=============
@@ -3117,6 +3322,24 @@ ordinary HTML (without bird tracks).
writes HTML with the Haskell code in bird tracks, so it can be copied
and pasted as literate Haskell source.
+Syntax highlighting
+===================
+
+Pandoc will automatically highlight syntax in fenced code blocks that
+are marked with a language name. (See [Extension:
+`inline_code_attributes`] and [Extension: `fenced_code_attributes`],
+above.) The Haskell library [highlighting-kate] is used for
+highlighting, which works in HTML, Docx, and LaTeX/PDF output.
+The color scheme can be selected using the `--highlight-style` option.
+The default color scheme is `pygments`, which imitates the default color
+scheme used by the Python library pygments, but pygments is not actually
+used to do the highlighting.
+
+To see a list of language names that pandoc will recognize, type
+`pandoc --version`.
+
+To disable highlighting, use the `--no-highlight` option.
+
Custom writers
==============
@@ -3137,18 +3360,135 @@ which you can modify according to your needs, do
Authors
=======
-© 2006-2013 John MacFarlane (jgm at berkeley dot edu). Released under the
+© 2006-2015 John MacFarlane (jgm@berkeley.edu). Released under the
[GPL], version 2 or greater. This software carries no warranty of
any kind. (See COPYRIGHT for full copyright and warranty notices.)
-Other contributors include Recai Oktaş, Paulo Tanimoto, Peter Wang,
-Andrea Rossato, Eric Kow, infinity0x, Luke Plant, shreevatsa.public,
-Puneeth Chaganti, Paul Rivier, rodja.trappe, Bradley Kuhn, thsutton,
-Nathan Gass, Jonathan Daugherty, Jérémy Bobbio, Justin Bogner, qerub,
-Christopher Sawicki, Kelsey Hightower, Masayoshi Takahashi, Antoine
-Latter, Ralf Stephan, Eric Seidel, B. Scott Michel, Gavin Beatty,
-Sergey Astanin, Arlo O'Keeffe, Denis Laxalde, Brent Yorgey, David Lazar,
-Jamie F. Olson, Matthew Pickering, Albert Krewinkel, mb21, Jesse
-Rosenthal.
+
+Contributors include
+Aaron Wolen,
+Albert Krewinkel,
+Alexander Kondratskiy,
+Alexander Sulfrian,
+Alexander V Vershilov,
+Alfred Wechselberger,
+Andreas Lööw,
+Andrew Dunning,
+Antoine Latter,
+Arlo O'Keeffe,
+Artyom Kazak,
+Ben Gamari,
+Beni Cherniavsky-Paskin,
+Bjorn Buckwalter,
+Bradley Kuhn,
+Brent Yorgey,
+Bryan O'Sullivan,
+B. Scott Michel,
+Caleb McDaniel,
+Calvin Beck,
+Christoffer Ackelman,
+Christoffer Sawicki,
+Clare Macrae,
+Clint Adams,
+Conal Elliott,
+Craig S. Bosma,
+Daniel Bergey,
+Daniel T. Staal,
+David Lazar,
+David Röthlisberger,
+Denis Laxalde,
+Douglas Calvert,
+Douglas F. Calvert,
+Eric Kow,
+Eric Seidel,
+Florian Eitel,
+François Gannaz,
+Freiric Barral,
+Fyodor Sheremetyev,
+Gabor Pali,
+Gavin Beatty,
+Greg Maslov,
+Grégory Bataille,
+Greg Rundlett,
+gwern,
+Gwern Branwen,
+Hans-Peter Deifel,
+Henry de Valence,
+Ilya V. Portnov,
+infinity0x,
+Jaime Marquínez Ferrándiz,
+James Aspnes,
+Jamie F. Olson,
+Jan Larres,
+Jason Ronallo,
+Jeff Arnold,
+Jeff Runningen,
+Jens Petersen,
+Jérémy Bobbio,
+Jesse Rosenthal,
+J. Lewis Muir,
+Joe Hillenbrand,
+John MacFarlane,
+Jonas Smedegaard,
+Jonathan Daugherty,
+Josef Svenningsson,
+Jose Luis Duran,
+Julien Cretel,
+Justin Bogner,
+Kelsey Hightower,
+Konstantin Zudov,
+Lars-Dominik Braun,
+Luke Plant,
+Mark Szepieniec,
+Mark Wright,
+Masayoshi Takahashi,
+Matej Kollar,
+Mathias Schenner,
+Matthew Pickering,
+Matthias C. M. Troffaes,
+Max Bolingbroke,
+Max Rydahl Andersen,
+mb21,
+Merijn Verstraaten,
+Michael Snoyman,
+Michael Thompson,
+MinRK,
+Nathan Gass,
+Neil Mayhew,
+Nick Bart,
+Nicolas Kaiser,
+Nikolay Yakimov,
+nkalvi,
+Paulo Tanimoto,
+Paul Rivier,
+Peter Wang,
+Philippe Ombredanne,
+Phillip Alday,
+Puneeth Chaganti,
+qerub,
+Ralf Stephan,
+Recai Oktaş,
+rodja.trappe,
+RyanGlScott,
+Scott Morrison,
+Sergei Trofimovich,
+Sergey Astanin,
+Shahbaz Youssefi,
+Shaun Attfield,
+shreevatsa.public,
+Simon Hengel,
+Sumit Sahrawat,
+takahashim,
+thsutton,
+Tim Lin,
+Timothy Humphries,
+Todd Sifleet,
+Tom Leese,
+Uli Köhler,
+Václav Zeman,
+Viktor Kronvall,
+Vincent,
+Wikiwide, and
+Xavier Olive.
[markdown]: http://daringfireball.net/projects/markdown/
[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
@@ -3169,6 +3509,7 @@ Rosenthal.
[Textile]: http://redcloth.org/textile
[MediaWiki markup]: http://www.mediawiki.org/wiki/Help:Formatting
[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
+[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules
[Haddock markup]: http://www.haskell.org/haddock/doc/html/ch03s08.html
[groff man]: http://developer.apple.com/DOCUMENTATION/Darwin/Reference/ManPages/man7/groff_man.7.html
[Haskell]: http://www.haskell.org/
@@ -3190,3 +3531,5 @@ Rosenthal.
[EPUB]: http://idpf.org/epub
[EPUBspine]: http://www.idpf.org/epub/301/spec/epub-publications.html#sec-spine-elem
[KaTeX]: https://github.com/Khan/KaTeX
+[CommonMark]: http://commonmark.org
+[highlighting-kate]: http://github.com/jgm/highlighting-kate
diff --git a/RELEASE-CHECKLIST b/RELEASE-CHECKLIST
index 0663e3f3a..fb786a9f0 100644
--- a/RELEASE-CHECKLIST
+++ b/RELEASE-CHECKLIST
@@ -2,6 +2,8 @@ _ Test, on linux, windows, mac (inc. website demos)
_ Finalize changelog
+_ make man/pandoc.1 and commit if needed
+
_ Tag release in git
_ Tag templates
@@ -12,6 +14,8 @@ _ Generate Windows package and copy to directory.
_ Generate Mac OSX package.
+_ Generate Ubuntu/Debian deb package.
+
- Add release on github (and upload files)
_ Upload to HackageDB
diff --git a/Setup.hs b/Setup.hs
index 7777a5133..312e1cf47 100644
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,34 +18,68 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import Distribution.Simple
import Distribution.Simple.PreProcess
-import Distribution.PackageDescription (PackageDescription(..), Executable(..))
+import Distribution.Simple.Setup (ConfigFlags(..))
+import Distribution.PackageDescription (PackageDescription(..), FlagName(..))
import System.Process ( rawSystem )
import System.FilePath ( (</>) )
import System.Directory ( findExecutable )
-import Distribution.Simple.Utils (info)
+import Distribution.Verbosity ( Verbosity )
+import Distribution.Simple.Utils (info, notice, installOrdinaryFiles)
+import Distribution.Simple.Setup
+import Distribution.Simple.Program (simpleProgram, Program(..))
+import Distribution.Simple.LocalBuildInfo
+import Data.Version
+import System.Process (readProcess)
+import Text.ParserCombinators.ReadP (readP_to_S, skipSpaces, eof)
+import Control.Monad (when)
+import qualified Control.Exception as E
main :: IO ()
main = defaultMainWithHooks $ simpleUserHooks {
-- enable hsb2hs preprocessor for .hsb files
hookedPreProcessors = [ppBlobSuffixHandler]
- -- ensure that make-pandoc-man-pages doesn't get installed to bindir
- , copyHook = \pkgdescr ->
- (copyHook simpleUserHooks) pkgdescr{ executables =
- [x | x <- executables pkgdescr, exeName x /= "make-pandoc-man-pages"] }
- , instHook = \pkgdescr ->
- (instHook simpleUserHooks) pkgdescr{ executables =
- [x | x <- executables pkgdescr, exeName x /= "make-pandoc-man-pages"] }
+ , hookedPrograms = [(simpleProgram "hsb2hs"){
+ programFindVersion = findHsb2hsVersion }]
+ , postCopy = installManPage
}
+findHsb2hsVersion :: Verbosity -> FilePath -> IO (Maybe Version)
+findHsb2hsVersion verb fp = do
+ let handleExitFailure :: IOError -> IO (Maybe Version)
+ handleExitFailure _ = return Nothing
+ E.handle handleExitFailure $ do
+ outp <- readProcess fp ["--version"] ""
+ case readP_to_S (do v <- parseVersion
+ skipSpaces
+ eof
+ return v) outp of
+ ((v,""):_) -> return (Just v)
+ _ -> return Nothing
+
ppBlobSuffixHandler :: PPSuffixHandler
-ppBlobSuffixHandler = ("hsb", \_ _ ->
+ppBlobSuffixHandler = ("hsb", \_ lbi ->
PreProcessor {
platformIndependent = True,
runPreProcessor = mkSimplePreProcessor $ \infile outfile verbosity ->
- do info verbosity $ "Preprocessing " ++ infile ++ " to " ++ outfile
- hsb2hsPath <- findExecutable "hsb2hs"
- case hsb2hsPath of
- Just p -> rawSystem p [infile, infile, outfile]
- Nothing -> error "hsb2hs is needed to build this program: cabal install hsb2hs"
- return ()
+ do let embedData = case lookup (FlagName "embed_data_files")
+ (configConfigurationsFlags (configFlags lbi)) of
+ Just True -> True
+ _ -> False
+ when embedData $
+ do info verbosity $ "Preprocessing " ++ infile ++ " to " ++ outfile
+ hsb2hsPath <- findExecutable "hsb2hs"
+ case hsb2hsPath of
+ Just p -> rawSystem p [infile, infile, outfile]
+ Nothing -> error "hsb2hs is needed to build this program: cabal install hsb2hs"
+ return ()
})
+
+installManPage :: Args -> CopyFlags
+ -> PackageDescription -> LocalBuildInfo -> IO ()
+installManPage _ flags pkg lbi = do
+ let verbosity = fromFlag (copyVerbosity flags)
+ let copydest = fromFlag (copyDest flags)
+ let mandest = mandir (absoluteInstallDirs pkg lbi copydest)
+ </> "man1"
+ notice verbosity $ "Copying man page to " ++ mandest
+ installOrdinaryFiles verbosity mandest [("man", "pandoc.1")]
diff --git a/appveyor.yml b/appveyor.yml
new file mode 100644
index 000000000..11551a88a
--- /dev/null
+++ b/appveyor.yml
@@ -0,0 +1,21 @@
+install:
+- cmd: 'git submodule update --init'
+- ps: |
+ choco install haskellplatform -version 2014.2.0.0 -y
+ # Haskell Platfrom package doesn't update PATH for the current shell instance
+
+ $env:Path += ";${env:ProgramFiles}\Haskell Platform\2014.2.0.0\bin"
+ $env:Path += ";${env:ProgramFiles}\Haskell Platform\2014.2.0.0\lib\extralibs\bin"
+ $env:Path += ";${env:ProgramFiles}\Haskell Platform\2014.2.0.0\mingw\bin"
+ cabal update
+ cabal install --only-dependencies --enable-tests -w "C:\Program Files\Haskell Platform\2014.2.0.0\bin\ghc-7.8.3"
+
+build_script:
+- ps: |
+ echo "PATH is $env:Path"
+ cabal configure --enable-tests -v2 -w "C:\Program Files\Haskell Platform\2014.2.0.0\bin\ghc-7.8.3"
+ cabal build
+
+test_script:
+- ps: |
+ cabal test
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
index bf67eaa4d..3fc70331f 100644
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -22,16 +22,19 @@ import System.Environment (getArgs)
import Data.Monoid
import Data.Maybe (mapMaybe)
import Debug.Trace (trace)
+import Text.Pandoc.Error
+import Control.Applicative
readerBench :: Pandoc
- -> (String, ReaderOptions -> String -> IO Pandoc)
+ -> (String, ReaderOptions -> String -> IO (Either PandocError Pandoc))
-> Maybe Benchmark
-readerBench doc (name, reader) = case lookup name writers of
- Just (PureStringWriter writer) ->
- let inp = writer def{ writerWrapText = True} doc
- in return $ bench (name ++ " reader") $ nfIO $
- (reader def{ readerSmart = True }) inp
- _ -> trace ("\nCould not find writer for " ++ name ++ "\n") Nothing
+readerBench doc (name, reader) =
+ case lookup name writers of
+ Just (PureStringWriter writer) ->
+ let inp = writer def{ writerWrapText = True} doc
+ in return $ bench (name ++ " reader") $ nfIO $
+ (fmap handleError <$> reader def{ readerSmart = True }) inp
+ _ -> trace ("\nCould not find writer for " ++ name ++ "\n") Nothing
writerBench :: Pandoc
-> (String, WriterOptions -> Pandoc -> String)
@@ -46,7 +49,7 @@ main = do
defaultOptions args
inp <- readFile "tests/testsuite.txt"
let opts = def{ readerSmart = True }
- let doc = readMarkdown opts inp
+ let doc = handleError $ readMarkdown opts inp
let readers' = [(n,r) | (n, StringReader r) <- readers]
let readerBs = mapMaybe (readerBench doc)
$ filter (\(n,_) -> n /="haddock") readers'
diff --git a/changelog b/changelog
index 97ba147e0..2ceef17ac 100644
--- a/changelog
+++ b/changelog
@@ -1,3 +1,1152 @@
+pandoc (1.15.0.6)
+
+ * `--self-contained`: Fixed overaggressive CSS minimization (#2301, 2286).
+ Previously `--self-contained` wiped out all spaces in CSS,
+ including semantically significant spaces. This was a regression
+ from 1.14.x.
+
+ * Markdown reader: don't allow bare URI links or autolinks in link
+ label (#2300). Added test cases.
+
+ * `Text.Pandoc.Parsing`, `uri`: Improved bare autolink detection (#2299).
+ Previously we disallowed `-` at the end of an autolink,
+ and disallowed the combination `=-`. This commit liberalizes the
+ rules for allowing punctuation in a bare URI, and adds test cases.
+ One potential drawback is that you can no longer put a bare
+ URI in em dashes like this:
+ `this uri---http://example.com---is an example.`
+ But in this respect we now match github's treatment of bare URIs.
+
+ * HTML writer: support speaker notes in dzslides.
+ With this change `<div class="notes">` and also `<div class="notes"
+ role="note">` will be output if `-t dzslides` is used. So we can
+ have speaker notes in dzslides too. Thanks to maybegeek.
+
+ * Updated dzslides template.
+
+ * Improved documentation of options to print system default files (#2298).
+ `--print-default-data-file` and `--print-default-template`.
+
+ * DokuWiki writer: use `$..$` for Math instead of `<math>..</math>`
+ (Tiziano Müller). MathJax seems currently to be the only maintained
+ math rendering extension for DokuWiki.
+
+ * `Text.Pandoc.Shared`: Changed `hierarchicalize` so it treats references
+ div as top-level header (#2294). This fixes a bug with `--section-divs`,
+ where the final references section added by pandoc-citeproc, enclosed in
+ its own div, got nested in the div for the section previous to it.
+
+ * Allow vector 0.11.
+
+ * Require cmark > 0.4.
+
+pandoc (1.15.0.5)
+
+ * HTML writer: Fixed email javascript obfuscation with `mailto:`
+ URLs (#2280). This fixes a potential security issue. Because
+ single quotes weren't being escaped in the link portion, a
+ specially crafted email address could allow javascript code injection.
+
+ * Markdown/HTML readers: Avoid parsing partial URLs like
+ `<www.pandoc.org/blah#foo>` as HTML tags (#2277).
+
+ * RST reader: allow inline formatting in definition list field
+ names (Lars-Dominik Braun).
+
+ * PDF: Make sure `--latex-engine-opt` goes before the filename
+ on the command line. LaTeX needs the argument to come after
+ the options (#1779).
+
+ * CommonMark writer: fixed tags used for super/subscript.
+
+ * ConTeXt template: activate hanging indent for definition lists
+ (mb21).
+
+ * Make cabal require `hsb2hs` >= 0.3.1 if `embed_data_files` specified.
+ This is done by adding `hookedPrograms` in `Setup.hs`, which allows us
+ to include `hsb2hs` in Build-Tools in cabal.
+
+ * Improved Windows installer (thanks to nkalvi).
+
+ + When per-machine installation is chosen, the system path
+ is updated instead of the user's.
+ + An appropriate default is used for per-machine installation
+ directory.
+ + Admin privileges are no longer required for a per-user install
+
+ * Travis: unpack sdist for build to catch packaging bugs.
+
+ * Improved documentation on where user templates go (#2272).
+
+pandoc (1.15.0.4)
+
+ * Added pandoc.1 man page to the repository. It is no longer
+ built as part of the cabal build process. (This proved too
+ fragile.) pandoc.1 can be regenerated (`make man/pandoc.1`)
+ when `README` is changed.
+
+ * Copying of the man page now respects `--destdir` (#2262).
+
+ * Improved error messages for filters. User is now informed if
+ the filter requires an interpreter that isn't found in the path,
+ or if the filter returns an error status.
+
+pandoc (1.15.0.3)
+
+ * Ensure target directory is created when installing man page.
+
+pandoc (1.15.0.2)
+
+ * Added files needed for building man page to Extra-Source-Files.
+
+pandoc (1.15.0.1)
+
+ * Man page is now built and installed as part of the cabal build
+ process. Removed Makefile target for man page.
+
+pandoc (1.15)
+
+ * Man page changes:
+
+ + Removed `--man1`, `--man5` options (breaking change).
+ + Removed `Text.Pandoc.ManPages` module (breaking API change).
+ + Makefile target for `man/man1/pandoc.1`. This uses pandoc to
+ create the man page from README using a custom template and filters.
+ + Added `man/` directory with template and filters needed to build
+ man page.
+ + We no longer have two man pages: `pandoc.1` and `pandoc_markdown.5`.
+ Now there is just pandoc.1, which has all the content from README.
+ This change was needed because of the extensive cross-references
+ between parts of the README.
+ + Removed old `data/pandoc.1.template` and
+ `data/pandoc_markdown.5.template`.
+
+ * OpenDocument writer: Do not add a carriage return after a hard
+ line break (Michael Chladek).
+
+ * ConTeXt writer:
+
+ + use `\goto` for internal links.
+ + Added a `%` at end for `\reference` to avoid spurious space.
+
+ * Ignore sandbox on 'make quick'
+
+pandoc (1.14.1)
+
+ * Added `--man1` and `--man5` options to pandoc, allowing pandoc
+ to generate its own man pages. Man pages are no longer automatically
+ generated in the build process (the process for this was too complex
+ and prone to failure, #2190). The `make-pandoc-man-pages` executable
+ has been removed. The `man/` directory has been removed, and man page
+ templates have been moved to `data/`. NOTE TO PACKAGERS: You will no
+ longer find pandoc's man pages in `man/`, but you can generate them using
+ `pandoc --man1 > pandoc.1` and `pandoc --man5 > pandoc_markdown.5`.
+
+ * Added new unexported module: `Text.Pandoc.ManPages`.
+
+ * `README` now acts like a data file (even though it isn't in
+ `data/`). So, for example, `pandoc --print-default-data-file README`
+ will produce the README.) This change was required for the `--man1`
+ and `--man5` options, since the man pages are produced from the
+ README, but it may be useful for other purposes as well.
+
+ * Allow `reference.docx` and `reference.odt` to be used with
+ `--print-default-data-file` and to shadow defaults if placed in
+ the user data directory. Note that as of 1.14, we no longer
+ include these files as data files; instead, we include their
+ components. This change causes pandoc to behave as if it has
+ these data files; they are constructed on demand when needed
+ using `getDefaultReferenceDocx` and `getDefaultReferenceODT`.
+
+ * Fixed regression in CSS parsing with `--self-contained` (#2224).
+ Pandoc 1.14.0.x used css-text to parse the CSS, but its parser
+ silently drops big sections of CSS. This commit replaces the
+ use of css-text with a small but principled CSS preprocessor,
+ which removes whitespace and comments and replaces `url()` with
+ base 64 data when possible.
+
+ * Use `https://` instead of `//` for MathJax and KaTeX CDN URLs (#1920).
+ This will allow math to work when pages are being viewed locally.
+
+ * `Text.Pandoc.Options`: Export `plainExtensions`.
+ These are the extensions used in `plain` output.
+
+ * LaTeX reader: Don't parse `_` and `^` as sub/superscript outside of
+ math mode; treat them as regular inline text. Normally these will
+ cause an error in LaTeX, but there are contexts (e.g. `alltt`
+ environments) where they are allowed.
+
+ * HTML reader: allow `<body>` to close `<head>`.
+
+ * DocBook reader: support `mediaobject`s and `figures` (#2184, mb21).
+
+ * RST reader: Fix reference names with special characters
+ (Lars-Dominik Braun).
+
+ * Textile writer: escape `+` and `-` as entities (#2225).
+
+ * DokuWiki writer: Use proper `<code>` tags for code blocks (#2213).
+
+ * Plain writer: don't use symbols for super/subscript (#2237).
+ Simplified code by using `plainExtensions`.
+
+ * InDesign writer: Properly escape URLs containing more than one
+ colon character (gohai).
+
+ * Docx writer: Make sure we use dist version of `reference.docx`
+ (and not the user's version) for certain settings. Taking some
+ settings values from a user-supplied reference.docx can lead to
+ corruption. This fixes a regression from the last release (#2249).
+
+ * `Text.Pandoc.Shared`: exports `getDefaultReferenceDocx` and
+ `getDefaultReferenceODT` (API change). These functions have been
+ removed from the Docx and ODT writers.
+
+ * LaTeX template (Xavier Olive):
+ + Added `CJKmainfont` and `CJKoptions` variables.
+ + Allow dvipsnames (e.g. `MidnightBlue`) for colors (Xavier Olive).
+
+ * Epub templates: use `author.role`, not `author.type`.
+
+ * Bump cmark version to >= 0.3.4.
+
+ * Improved Windows installer (#2205, thanks to nkalvi).
+ Users can now select a per-user or systemwide install, and can set
+ the installation path. At the end of installation, the install location
+ is given. The install location is also now given in the list of
+ installed programs in Control Panel. Cleaner WiX syntax is used for
+ setting the path.
+
+ * Added `download_stats` target to Makefile.
+
+pandoc (1.14.0.4)
+
+ * Added missing commonmark template.
+
+ * Improved try pandoc (moved button, show raw command).
+
+pandoc (1.14.0.3)
+
+ * Allow compilation with syb 0.5.*.
+
+ * Custom writer: fixed some compiler warnings for ghc < 7.10.
+
+pandoc (1.14.0.2)
+
+ * Allow building with hslua 0.4.
+
+pandoc (1.14.0.1)
+
+ * Fixed problem with building of `reference.docx` and `reference.odt`
+ when the `embed_data_files` flag is used. Instead of having a phase
+ of the build where `reference.docx` and `reference.odt` are created
+ from their constituent data files, we now construct these archives
+ from their constituents when a `docx` or `odt` is built. The
+ constituent files have been moved from `extra-source-files` to
+ `data-files`, and `reference.docx` and `reference.odt` have been
+ removed. Users can create their own `reference.docx` or
+ `reference.odt` by using pandoc to create a simple `docx` or `odt`.
+ `make-reference-files.hs` has been removed, simplifying the build
+ process (#2187)
+
+ * Don't include generated man pages in extra-source-files (#2189).
+
+ * Bumped upper bound for aeson.
+
+ * ConTeXt writer: create internal link anchors for Div elements with
+ identifiers. (This is needed for linked citations to work.)
+
+pandoc (1.14)
+
+ [new features]
+
+ * Added `commonmark` as input and output format.
+
+ * Added `--verbose` flag for debugging output in PDF production (#1840,
+ #1653).
+
+ * Allow wildcards in `--epub-embed-font` arguments (#1939).
+
+ * Added `--latex-engine-opt` option (#969, #1779, Sumit Sahrawat).
+
+ * Added `shortcut_reference_links` extension (Konstantin Zudov, #1977).
+ This is enabled by default for those markdown flavors that
+ support reading shortcut reference links, namely: `markdown`,
+ `markdown_strict`, `markdown_github`, `markdown_php`.
+ If the extension is enabled, the reader parses shortcut reference
+ links like `[foo]`, and the writer creates such links unless doing
+ so would cause problems. Users of markdown flavors that support
+ shortcut reference links should not notice a difference in reading
+ markdown, but the markdown pandoc produces may differ.
+ If shortcut links are not desired, the extension can be disabled
+ in the normal way.
+
+ [behavior changes]
+
+ * `--toc` is now supported for `docx` output (#458, Nikolay Yakimov).
+ A "dirty" TOC is created at the beginning of document.
+ It can be regenerated after the document has been opened.
+
+ * An implicit `--filter pandoc-citeproc` is now triggered only when the
+ `--bibliography` option is used, and not when the `bibliography`
+ field in metadata is specified (#1849).
+
+ * Markdown reader:
+
+ + Reference links with `implicit_header_references` are no longer
+ case-sensitive (#1606).
+ + Definition lists no longer require indentation for first line (#2087).
+ Previously the body of the definition (after the `:` or `~` marker)
+ needed to be in column 4. This commit relaxes that requirement,
+ to better match the behavior of PHP Markdown Extra. So, now
+ this is a valid definition list:
+
+ foo
+ : bar
+ + Resolve a potentially ambiguity with table captions:
+
+ foo
+
+ : bar
+
+ -----
+ table
+ -----
+
+ Is "bar" a definition, or the caption for the table? We'll count
+ it as a caption for the table.
+ + Disallow headerless pipe tables (#1996), to conform to GFM and PHP
+ Markdown Extra. Note: If you have been using headerless pipe tables,
+ this change may cause existing tables to break.
+ + Allow pipe tables with header but no body (#2017).
+ + Allow a digit as first character of a citation key (Matthias Troffaes).
+ See https://github.com/jgm/pandoc-citeproc/issues/97
+
+ * LaTeX reader:
+
+ + Don't limit includes to `.tex` extension (#1882).
+ If the extension is not `.tex`, it must be given explicitly in
+ the `\input` or `\include`.
+
+ * Docx reader:
+
+ + Allow numbering in the style file. This allows inherited styles
+ with numbering (lists) (Jesse Rosenthal).
+
+ * Org reader:
+
+ + Support smart punctuation (Craig Bosma).
+ + Drop trees with a :noexport: tag (Albert Krewinkel). Trees having a
+ `:noexport:` tag set are not exported. This mirrors org-mode.
+ + Put header tags into empty spans (Albert Krewinkel, #2160).
+ Org mode allows headers to be tagged: `* Headline :TAG1:TAG2`.
+ Instead of being interpreted as part of the headline, the tags are now
+ put into the attributes of empty spans. Spans without textual content
+ won't be visible by default, but they are detectable by filters. They
+ can also be styled using CSS when written as HTML.
+ + Generalize code block result parsing (Albert Krewinkel).
+ Previously, only code blocks were recognized as result blocks;
+ now, any kind of block can be the result.
+
+ * Append newline to the LineBreak in Dokuwiki, HTML, EPUB,
+ LaTeX, MediaWiki, OpenDocument, Texinfo writers (#1924, Tim Lin).
+
+ * HTML writer:
+
+ + Add "inline" or "display" class to math spans (#1914).
+ This allows inline and display math to be styled differently.
+ + Include raw latex blocks if `--mathjax` specified (#1938).
+ + Require highlighting-kate >= 0.5.14 (#1903).
+ This ensures that all code blocks will be wrapped in a `div`
+ with class `sourceCode`. Also, the default highlighting CSS
+ now adds `div.sourceCode { x-overflow: auto; }`, which means
+ that code blocks (even with line numbers) will acquire a scroll
+ bar on screens too small to display them (e.g. mobile phones).
+ See also jgm/highlighting-kate#65.
+
+ * LaTeX writer:
+
+ + Use a declaration for tight lists (Jose Luis Duran, Joseph
+ Harriott). Previously, pandoc hard-coded some commands to make
+ tight lists in LaTeX. Now we use a custom command instead,
+ allowing the styling to be changed in a macro in the header.
+ (Note: existing templates may need to be modified to include
+ the definition of this macro. See the current template.)
+ + Beamer output: if the header introducing a slide has the
+ class `fragile`, add the `[fragile]` option to the slide (#2119).
+
+ * MediaWiki writer:
+
+ + Use `File:` instead of the deprecated `Image:` for images and
+ other media files (Greg Rundlett).
+
+ * DocBook writer:
+
+ + Render a `Div (id,_,_) [Para _]` element as a `para` element
+ with an `id` attribute. This makes links to citations work in
+ DocBook with pandoc-citeproc.
+
+ * RST writer:
+
+ + Normalize headings to sequential levels (Nikolay Yakimov).
+ This is pretty much required by docutils.
+ + Treat headings in block quotes, etc as rubrics (Nikolay Yakimov).
+ + Better handling of raw latex inline (#1961). We use
+ `` :raw-latex:`...` `` and add a definition for this role to
+ the template.
+
+ * EPUB writer:
+
+ + Remove `linear=no` from cover `itemref` (#1609).
+ + Don't use `sup` element for epub footnotes (#1995).
+ Instead, just use an a element with class `footnoteRef`.
+ This allows more styling options, and provides better results
+ in some readers (e.g. iBooks, where anything inside the a
+ tag breaks popup footnotes).
+ + Take TOC title from `toc-title` metadata field.
+
+ * Docx writer:
+
+ + Implemented `FirstParagraph` style (Jesse Rosenthal).
+ Following the ODT writer, we add the `FirstParagraph` style to the
+ first text paragraph following an image, blockquote, table, heading,
+ or beginning of document. This allows it to be styled differently.
+ The default is for it to be the same as `Normal`.
+ + Added `BodyText` style (Jesse Rosenthal).
+ We apply a `BodyText` style to all unstyled paragraphs. This is,
+ essentially, the same as `Normal`, except that since not everything
+ inherits from `BodyText` (the metadata won't, for example, or
+ the headers or footnote numbers), we can change the text in the body
+ without having to make exceptions for everything. If we do want to
+ change *everything*, we can still do it through `Normal`.
+ + Altered `Blockquote` style slightly (Jesse Rosenthal).
+ Since `BlockQuote` derives from `BodyText`, we just want to specify
+ by default that it won't indent, regardless of what `BodyText` does.
+ Note that this will not produce any visible difference in the default
+ configuration.
+ + Take TOC title from `toc-title` metadata field (Nikolay Yakimov).
+ + Added a style to figure images (Nikolay Yakimov).
+ Figures with empty captions use style `Figure`.
+ Figures with nonempty captions use style `Figure with Caption`, which
+ is based on `Figure`, and additionally has `keepNext` set.
+
+ * ODT writer:
+
+ + Added figure captions (Nikolay Yakimov). The following styles are
+ used for figures:
+ `Figure` -- for figure with empty caption),
+ `FigureWithCaption` (based on `Figure`) -- for figure with caption,
+ `FigureCaption` (based on `Caption`) -- for figure captions.
+ Also, `TableCaption` (based on `Caption`) is used for table captions.
+
+ [API changes]
+
+ * New `Text.Pandoc.Error` module with `PandocError` type
+ (Matthew Pickering).
+
+ * All readers now return `Either PandocError Pandoc` instead of `Pandoc`
+ (Matthew Pickering). This allows better handling of errors.
+
+ * Added `Text.Pandoc.Writers.CommonMark`, exporting `writeCommonMark`.
+
+ * Added `Text.Pandoc.Readers.CommonMark`, exporting `readCommonMark`.
+
+ * Derive `Data` and `Typeable` instances for `MediaBag`, `Extension`,
+ `ReaderOptions`, `EPUBVersion`, `CiteMethod`, `ObfuscationMethod`,
+ `HTMLSlideVariant`, `TrackChanges`, `WriterOptions` (Shabbaz
+ Youssefi).
+
+ * New `Ext_shortcut_reference_links` constructor for `Extension`
+ (Konstantin Zudov).
+
+ [bug fixes]
+
+ * Markdown reader:
+
+ + Allow smart `'` after inline math (#1909, Nikolay Yakimov).
+ + Check for tex macros after indented code (#1973).
+ + Rewrote `charsInBalancedBrackets` for efficiency.
+ + Make sure a closing `</div>` doesn't get included in a
+ definition list item (#2127).
+ + Don't parse bracketed text as citation if it might be a link,
+ image, or footnote (Nikolay Yakimov).
+ + Require space after key in mmd title block (#2026, Nikolay
+ Yakimov). Require space after key-value delimiter colon in mmd title
+ block.
+ + Require nonempty value in mmd title block (Nikolay Yakimov).
+ + Disable all metadata block extensions when parsing
+ metadata field values (#2026, Nikolay Yakimov). Otherwise we
+ could get a mmd title block inside YAML metadata, for example.
+
+ * HTML reader:
+
+ + Improve self-closing tag detection in `htmlInBalanced` (#2146).
+ + Handle tables with `<th>` in body rows (#1859, mb21).
+ + Fixed `htmlTag` (#1820). If the tag parses as a comment, we check
+ to see if the input starts with `<!--`. If not, it's bogus comment
+ mode and we fail `htmlTag`.
+ + Handle `base` tag; if it has an `href` value, this is added to
+ all relative URLs in links and images.
+
+ * DocBook reader:
+
+ + Look inside "info" elements for section titles (#1931).
+
+ * Docx reader:
+
+ + Parse images in deprecated vml format (Jesse Rosenthal).
+ + Allow sub/superscript verbatims (Jesse Rosenthal).
+ Verbatim usually shuts off all other run styles, but we don't want it
+ to shut off sub/superscript.
+
+ * LaTeX reader:
+
+ + Handle `tabular*` environment (#1850).
+ Note that the table width is not actually parsed or taken into
+ account, but pandoc no longer chokes on it.
+ + Ignore options in `\lstinline` rather than raising error (#1997).
+ + Add some test cases for simple tables (Mathias Schenner).
+ + Handle valign argument in tables (Mathias Schenner) (currently
+ we just ignore this).
+ + Allow non-empty colsep in tables (Mathias Schenner).
+ The `tabular` environment allows non-empty column separators
+ with the "@{...}" syntax. Previously, pandoc would fail to
+ parse tables if a non-empty colsep was present. With this
+ commit, these separators are still ignored, but the table gets
+ parsed. A test case is included.
+ + Recognize `\newpage` as a block command.
+ + Allow block content in \title{} (#2001).
+ + Check for block-level newcommand aliases in blockCommand (Nikolay
+ Yakimov).
+ + Guard against paragraph starting with inline macro (Nikolay Yakimov).
+ + Properly gobble spaces after `\\` (#2007).
+
+ * Textile reader:
+
+ + Handle newlines in table cells, and empty cells (#1919).
+
+ * Org reader:
+
+ + Allow image links with non-image targets (Hans-Peter Deifel).
+ This matches behavior of Org-Mode for links like
+ `[[http://example.com][https://www.haskell.org/static/img/logo.png]]`.
+
+ * Docbook writer:
+
+ + Don't print empty id attributes (thanks to Steve Horne).
+
+ * HTML writer:
+
+ + Fixed list-style-type for numbered example lists.
+ Should be "decimal," not "example" (#1902).
+ + Do not omit missing `alt` attribute on `img` tag (#1131,
+ Konstantin Zudov).
+ + Allow multiple colgroups in table (#2122).
+ + In revealjs, ensure that lists in speaker notes don't add "fragment"
+ classes, which can cause additional keypresses to be needed to
+ advance a slide (#1394).
+
+ * LaTeX writer:
+
+ + Don't escape `$` in URL (#1913).
+ + Don't use listings in headers (Matthew Pickering, #1963).
+ + Recognize book documentclass if set in metadata (#1971).
+ This sets `--chapters` implicitly if the documentclass in metadata
+ is a book documentclass. Previously this was done only if a book
+ documentclass was set in a variable.
+ + Add a `\label` in `\hyperdef` for Div, Span (or links don't work).
+ + Make `mainlang` work when `lang` is in metadata (#2174).
+
+ * Texinfo writer:
+
+ + Fix wrapping by using breakable spaces (Tim Lin).
+
+ * RST writer:
+
+ + Fixed toc depth in RST writer. Previously the depth was being
+ rendered as a floating point number with a decimal point.
+
+ * Markdown writer:
+
+ + Improved escaping (#2086). `<` should not be escaped as `\<`, for
+ compatibility with original Markdown. We now escape `<` and `>`
+ with entities. Also, we now backslash-escape square brackets.
+ + Avoid introducing spurious list items through wrapping (#1946).
+ + Don't emit span tags if plain or raw HTML disabled.
+
+ * MediaWiki writer:
+
+ + Convert spaces to underscores in wikilink URL (#1982), like MediaWiki.
+
+ * AsciiDoc writer:
+
+ + Insert some needed blank lines (#1860).
+ + Avoid wrapping after list marker (#1858).
+
+ * EPUB writer:
+
+ + Properly handle internal links to IDs in spans, divs (#1884).
+ + Use plain writer for metadata dc: fields (#2121).
+ This gives better results when we have, e.g. multiple paragraphs.
+ Note that tags aren't allowed in these fields.
+ + Properly handle image links without an extension (#1855).
+ + Improved chapter splitting and internal link rewriting (#1887,
+ #2162, #2163). This will ensure that internal links work and
+ that the references section produced by pandoc-citeproc is
+ in its own chapter.
+ + Fixed handling of svg images (#2183).
+
+ * ICML writer:
+
+ + Better handling of raw blocks and inlines (#1951).
+ Previously these were always escaped and printed verbatim.
+ Now they are ignored unless the format is `icml`, in which
+ case they are passed through unescaped.
+ + Fixed image URIs in ICML output (gohai).
+
+ * Custom writer:
+
+ + Raise error if loadstring returns an error status.
+ + Raise `PandocLuaException` instead of using 'error'.
+ Eventually we'll change the return type so that no exception
+ is involved, but at least this can be trapped.
+ + Use UTF-8 aware bytestring conversion.
+ + Set foreign encoding to UTF-8 (Nikolay Yakimov, #2101, #1634).
+ Also factored out ByteString, since it's only used as an intermediate
+ representation.
+
+ * Docx writer:
+
+ + Copy hyphenation settings from reference.docx (Nikolay Yakimov).
+ + Filter out illegal XML characters (#1992, Matthew Pickering).
+ + Added `noProof` to docx syntax highlighting `SourceCode` style.
+ + Added footnotes id -1 and 0 (Jesse Rosenthal).
+ Word uses, by default, footnotes with id -1 and 0 for separators. If a
+ user modifies `reference.docx`, they will end up with a `settings.xml`
+ file that references these footnotes, but no such footnotes in the
+ document. This will produce a corruption error. Here we add these to the
+ document and `settings.xml` file, so future modifications won't break
+ the file.
+ + Handle lists correctly inside table cells (Jesse Rosenthal).
+ Previously we didn't transform lists inside table cells.
+ + Set firstRow information in tables (Nikolay Yakimov).
+ + Don't replace `SourceCode` style in `reference.docx` if it is defined
+ there (Nikolay Yakimov, #1872). If `--no-highlight` specified, remove
+ any `SourceCode` and `*Tok` styles in `reference.docx`.
+ + Attempt to match international style names (#1607, Nikolay Yakimov).
+ + Set these styles as custom (Nikolay Yakimov): `Author`, `Abstract`,
+ `Compact`, `Image Caption`, `Table Caption`, `Definition Term`,
+ `Definition`, `First Paragraph`.
+ + Rename these styles to correspond with Word `Normal.dotm` (Nikolay
+ Yakimov): `Block Quote -> Block Text`, `Link -> Hyperlink`,
+ `Footnote Ref -> Footnote Reference`.
+ + Added `Caption` style (Nikolay Yakimov).
+ + Changed these styles' inheritance (Nikolay Yakimov):
+ `Image Caption <- Caption`, `Table Caption <- Caption`.
+ + Remove `SourceCode` style from `reference.docx` (#1872).
+ This is added automatically by the docx writer.
+ + Added toc heading style to `reference.docx` (Nikolay Yakimov).
+
+ * `Text.Pandoc.PDF`
+
+ + Don't suggest "Try xelatex" if xelatex already in use (mb21, #1832).
+ + More comprehensible errors on image conversion (#2067).
+ EPS can't be supported without shelling out to something like
+ ImageMagick, but at least we can avoid mysterious error messages.
+
+ * `Text.Pandoc.Shared`:
+
+ + Make safeRead safe (#1801, Matthew Pickering).
+ + Addded `mapLeft`, `hush` (Matthew Pickering).
+
+ * `Text.Pandoc.Pretty`:
+
+ + Remove partial function (Matthew Pickering).
+
+ * `Text.Pandoc.SelfContained`:
+
+ + Add `;charset=utf-8` to script mime type if missing (#1842).
+ + Improved building of data URIs (#1940). Now base64 is used except
+ for `text/*` mime types.
+ + `cssURLs` no longer tries to fetch fragment URLs (#2121).
+ + Properly handle data URIs in css urls (#2129).
+ Use a proper CSS parser (adds dependency on `text-css`).
+
+ * `Text.Pandoc.UTF8`:
+
+ + Better handling of bare CRs in input files (#2132).
+ Previously we just stripped them out; now we convert
+ other line ending styles to LF line endings.
+
+ * `Text.Pandoc.ImageSize`:
+
+ + Fixed some exif header parsing bugs (#1834).
+ + Make imageSize return an Either, not a Maybe (#1834).
+ Use `runGetOrFail` (with `binary >= 0.7`) to return `Left` on
+ parse failure (rather than `error`).
+ + Improved warnings when image size can't be determined.
+ + Removed error landmines (Matthew Pickering).
+
+ * Added woff2 to MIME types (Alfred Wechselberger).
+
+ * pandoc: When a binary input format is used, warn that file
+ arguments past the first one are being ignored (Matthew Pickering).
+
+ [template changes]
+
+ * LaTeX template:
+
+ + Degrade gracefully if `\paragraph` not defined.
+ + Include `grffile` together with `graphicx` (#2074).
+ This properly handles filenames containing spaces and dots.
+ + Redefine `\paragraph`, `\subparagraph`... to behave more
+ like section headers (#1658).
+ + Import hyperref before polyglossia to avoid an error with xelatex,
+ "please load package hyperref before bidi package" (Nick Bart).
+ + Added `toccolor` variable to control link color in toc (Kaixhin).
+
+ * LaTeX, Beamer templates:
+
+ + Provide `\tightlist`, which is now used by the LaTeX writer.
+ + Use polyglossia in beamer (#85).
+ + Use `bibliography` instead of `biblio-files`
+ (#1661). Also use `\addbibresource` instead of `\bibliography` for
+ biblatex.
+ + Added `setotherlanguages` in polyglossia. This uses an `otherlang`
+ variable that is derived from a comma-separated list in `lang`;
+ the last language is `mainlang` and the others are `otherlang`.
+
+ * EPUB templates:
+
+ + Use `div`, not `p`, for "rights" on title page.
+ + Added header-includes, include-before, include-after (#1987).
+
+ * OpenDocument template:
+
+ + Use `text:p` instead of `text:h` for title.
+ Using `text:h` causes problems with numbering. Closes #2059.
+ Thansk to @nkalvi for diagnosing this.
+
+ * reveal.js template:
+
+ + Link to non-minified css, js. The minified versions no longer
+ ship with the library.
+ + Correctly include style CSS (#1949).
+ + New configurable options options: `center`, `maxScale`, `slideNuber`
+ (Dmitry Smirnov, pandoc-templates#89).
+ + Moved custom CSS after theme. This allows custom CSS to modify
+ themes, instead of being replaced by them.
+ + Allow `center` to be set to false.
+
+ [under the hood improvements]
+
+ * Removed pre-built `reference.docx` and `reference.odt` (Nikolay
+ Yakimov). Instead the repository now includes the component text files,
+ and the zipped binaries are built from these using a helper
+ program, `make-reference-files`. This should make maintenance of
+ these components easier going forward.
+
+ * `Text.Pandoc.Parsing`:
+
+ + Added new `<+?>` combinator (Nikolay Yakimov).
+ + Added `stateHeaderKeys` to `ParserState`.
+
+ * `make_deb.sh` fixes:
+
+ + Detect architecture.
+ + Add Installed-Size to debian package control file (#1900).
+ + Use `fakeroot` to get permissions right.
+ + Use `mkdir` and `cp` instead of `install`.
+ + Set permissions of directories to 755.
+ + Install in `/usr` rather than `/usr/local`.
+ + Compress man pages.
+ + Combine copyright files for `pandoc`, `pandoc-citeproc`.
+
+ * Added `Text.Pandoc.Compat.Locale` and `old-locale` flag
+ to assist with transition to `time` 1.5.
+
+ * Updated CONTRIBUTING.md with information about issue tags (Matthew
+ Pickering).
+
+ * Updated travis installs to the new sudo-less syntax (Tim Lin).
+
+ * Updated dependency version bounds.
+
+ * EPUB tests: don't use `joinPath`, which varies across platforms.
+ Instead, use a forward-slash to join paths, regardless of the
+ platform. This matches the way `MediaBag` now works.
+
+ * Clarify JSON input and output in usage message (Caleb McDaniel).
+
+ * Improved INSTALL instructions.
+
+ * Always build man pages. Removed make-pandoc-man-pages flag.
+
+ * Makefile: removed man target, now that we generate man pages by default.
+
+ * README:
+
+ + Fixed typos (J. Lewis Muir).
+ + Added documentation on backtick_code_blocks (#2135, Nikolay Yakimov).
+ + Added note on in-field markup in biblio databases (Nick Bart).
+ + Fixed misleading example of raw HTML block.
+ + Various minor formatting and consistency fixes for the program
+ options (Andreas Lööw).
+ + Made definition lists for options all "loose" for consistency.
+ + Added YAML biblio format to table, and note on `pandoc-citeproc`'s
+ `--bib2json` and `--bib2yaml` options (Nick Bart).
+ + Removed obsolete reference to `mods2yaml` (Nick Bart).
+ + Added section on syntax highlighting.
+ + Documented `toccolor` variable.
+
+pandoc (1.13.2.1)
+
+ * Updated to build with ghc 7.10.1.
+
+ * Bumped package upper bounds for filepath, blaze-html,
+ blaze-markup.
+
+pandoc (1.13.2)
+
+ * TWiki Reader: add new new twiki reader (API chaneg, Alexander Sulfrian).
+
+ * Markdown reader:
+
+ + Better handling of paragraph in div (#1591).
+ Previously text that ended a div would be parsed as Plain
+ unless there was a blank line before the closing div tag.
+ + Don't treat a citation as a reference link label (#1763).
+ + Fix autolinks with following punctuation (#1811).
+ The price of this is that autolinked bare URIs can no longer
+ contain `>` characters, but this is not a big issue.
+ + Fix `Ext_lists_without_preceding_blankline` bug (#1636, Artyom).
+ + Allow `startnum` to work without `fancy_lists`. Formerly
+ `pandoc -f markdown-fancy_lists+startnum` did not work properly.
+
+ * RST reader (all Daniel Bergey):
+
+ + Parse quoted literal blocks (#65). RST quoted literal blocks are
+ the same as indented literal blocks (which pandoc already supports)
+ except that the quote character is preserved in each line.
+ + Parse RST class directives. The class directive accepts one or more
+ class names, and creates a Div value with those classes. If the
+ directive has an indented body, the body is parsed as the children of
+ the Div. If not, the first block folowing the directive is made a
+ child of the Div. This differs from the behavior of rst2xml, which
+ does not create a Div element. Instead, the specified classes are
+ applied to each child of the directive. However, most Pandoc Block
+ constructors to not take an Attr argument, so we can't duplicate this
+ behavior.
+ + Warn about skipped directives.
+ + Literal role now produces Code. Code role should have "code" class.
+ + Improved support for custom roles
+
+ - Added `sourceCode` to classes for `:code:` role, and anything
+ inheriting from it.
+ - Add the name of the custom role to classes if the Inline
+ constructor supports Attr.
+ - If the custom role directive does not specify a parent role,
+ inherit from the `:span:` role.
+
+ This differs somewhat from the `rst2xml.py` behavior. If a custom
+ role inherits from another custom role, Pandoc will attach both
+ roles' names as classes. `rst2xml.py` will only use the class of
+ the directly invoked role (though in the case of inheriting from a
+ `:code:` role with a `:language:` defined, it will also provide the
+ inherited language as a class).
+ + Warn about ignored fields in role directives.
+
+ * LaTeX reader:
+
+ + Parse label after caption into a span instead of
+ inserting an additional paragraph of bracketed text (#1747).
+ + Parse math environments as inline when possible (#1821).
+ + Better handling of `\noindent` and `\greektext` (#1783).
+ + Handle `\texorpdfstring` more gracefully.
+ + Handle `\cref` and `\sep` (Wikiwide).
+ + Support `\smartcite` and `\Smartcite` from biblatex.
+
+ * HTML reader:
+
+ + Retain display type of MathML output (#1719, Matthew Pickering).
+ + Recognise `<br>` tags inside `<pre>` blocks (#1620, Matthew Pickering).
+ + Make `embed` tag either block or inline (#1756).
+
+ * DocBook reader:
+
+ + Handle `keycombo`, `keycap` (#1815).
+ + Get string content in inner tags for literal elements (#1816).
+ + Handle `menuchoice` elements better, with a `>` between (#1817).
+ + Include `id` on section headers (#1818).
+ + Document/test "type" as implemented (Brian O'Sullivan).
+ + Add support for calloutlist and callout (Brian O'Sullivan).
+ We treat a calloutlist as a bulleted list. This works well in practice.
+ + Add support for `classname` (Bryan O'Sullivan).
+
+ * Docx reader:
+
+ + Fix window path for image lookup (Jesse Rosenthal).
+ Don't use os-sensitive "combine", since we always want the paths in our
+ zip-archive to use forward-slashes.
+ + Single-item headers in ordered lists are headers (Jesse Rosenthal).
+ When users number their headers, Word understands that as a single item
+ enumerated list. We make the assumption that such a list is, in fact,
+ a header.
+ + Rewrite rewriteLink to work with new headers (Jesse Rosenthal).
+ There could be new top-level headers after making lists, so we have to
+ rewrite links after that.
+ + Use polyglot header list (Jesse Rosenthal).
+ We're just keeping a list of header formats that different languages
+ use as their default styles. At the moment, we have English, German,
+ Danish, and French. We can continue to add to this.
+ This is simpler than parsing the styles file, and perhaps less
+ error-prone, since there seems to be some variations, even within a
+ language, of how a style file will define headers.
+ + Remove header class properly in other langs (Jesse Rosenthal).
+ When we encounter one of the polyglot header styles, we want to remove
+ that from the par styles after we convert to a header. To do that, we
+ have to keep track of the style name, and remove it appropriately.
+ + Account for external link URLs with anchors. Previously, if a URL
+ had an anchor, the reader would incorrectly identify it as an
+ internal link and return only the anchor as URL. (Caleb McDaniel)
+ + Fix for Issue #1692 (i18n styles) (Nikolay Yakimov).
+
+ * Org reader:
+
+ + Added state changing blanklines (Jesse Rosenthal).
+ This allows us to emphasize at the beginning of a new paragraph (or, in
+ general, after blank lines).
+ + Fixed bug with bulleted lists:
+
+ - a
+ - b
+ * c
+
+ was being parsed as a list, even though an unindented `*`
+ should make a heading. See
+ <http://orgmode.org/manual/Plain-lists.html#fn-1>.
+ + Org reader: absolute, relative paths in link (#1741, Albert
+ Krewinkel). The org reader was too restrictive when parsing links;
+ some relative links and links to files given as absolute paths
+ were not recognized correctly.
+ + Org reader: allow empty links (jgm/gitit#471, Albert Krewinkel).
+ This is important for use in gitit, which uses empty links
+ for wikilinks.
+ + Respect indent when parsing Org bullet lists (#1650, Timothy
+ Humphries). Fixes issue with top-level bullet list parsing.
+ + Fix indent issue for definition lists (Timothy Humphries,
+ see #1650, #1698, #1680).
+ + Parse multi-inline terms correctly in definition list (#1649,
+ Matthew Pickering).
+ + Fix rules for emphasis recognition (Albert Krewinkel).
+ Things like `/hello,/` or `/hi'/` were falsy recognized as emphasised
+ strings. This is wrong, as `,` and `'` are forbidden border chars and
+ may not occur on the inner border of emphasized text.
+ + Drop COMMENT document trees (Albert Krewinkel).
+ Document trees under a header starting with the word `COMMENT` are
+ comment trees and should not be exported. Those trees are dropped
+ silently (#1678).
+ + Properly handle links to `file:target` (Albert Krewinkel).
+ Org links like `[[file:target][title]]` were not handled correctly,
+ parsing the link target verbatim. The org reader is changed such that
+ the leading `file:` is dropped from the link target (see #756, #1812).
+ + Parse LaTeX-style MathML entities (#1657, Albert Krewinkel).
+ Org supports special symbols which can be included using LaTeX syntax,
+ but are actually MathML entities. Examples for this are
+ `\nbsp` (non-breaking space), `\Aacute` (the letter A with accent acute)
+ or `\copy` (the copyright sign ©)
+
+ * EPUB reader:
+
+ + URI handling improvements. Now we outsource most of the work to
+ `fetchItem'`. Also, do not include queries in file extensions (#1671).
+
+ * LaTeX writer:
+
+ + Use `\texorpdfstring` for section captions when needed (Vaclav Zeman).
+ + Handle consecutive linebreaks (#1733).
+ + Protect graphics in headers (Jesse Rosenthal).
+ Graphics in `\section`/`\subsection` etc titles need to be `\protect`ed.
+ + Put `~` before header in list item text (Jesse Rosenthal).
+ Because of the built-in line skip, LaTeX can't handle a section header
+ as the first element in a list item.
+ + Avoid using reserved characters as `\lstinline` delimiters (#1595).
+ + Better handling of display math in simple tables (#1754).
+ We convert display math to inline math in simple tables,
+ since LaTeX can't deal with display math in simple tables.
+ + Escape spaces in code (#1694, Bjorn Buckwalter).
+
+ * MediaWiki writer:
+
+ + Fixed links with URL = text. Previously these were rendered as bare
+ words, even if the URL was not an absolute URL (#1825).
+
+ * ICML writer:
+
+ + Don't force all citations into footnotes.
+
+ * RTF writer:
+
+ + Add blankline at end of output (#1732, Matthew Pickering).
+
+ * RST writer:
+
+ + Ensure blank line after figure.
+ + Avoid exces whitespace after last list item (#1777).
+ + Wrap line blocks with spaces before continuations (#1656).
+ + Fixed double-rendering of footnotes in RST tables (#1769).
+
+ * DokuWiki writer:
+
+ + Better handling of block quotes. This change ensures that
+ multiple paragraph blockquotes are rendered using native `>`
+ rather than as HTML (#1738).
+ + Fix external images (#1739). Preface relative links with ":",
+ absolute URIs without. (Timothy Humphries)
+
+ * HTML writer:
+
+ + Use protocol-relative URL for mathjax.
+ + Put newline btw img and caption paragraph.
+ + MathML now outputted with tex annotation (#1635, Matthew Pickering).
+ + Add support for KaTeX HTML math (#1626, Matthew Pickering).
+ This adds `KaTeX` to `HTMLMathMethod` (API change).
+ + Don't double render when `email-obfuscation=none` (#1625, Matthew
+ Pickering).
+ + Make header attributes work outside top level (#1711).
+ Previously they only appeared on top level header elements.
+ Now they work e.g. in blockquotes.
+
+ * ODT writer:
+
+ + Correctly handle images without extensions (#1729).
+ + Strip querystring in ODT write (#1682, Todd Sifleet).
+
+ * FB2 writer:
+
+ + Add newline to output.
+
+ * EPUB writer:
+
+ + Don't add `sourceURL` to absolute URIs (#1669).
+ + Don't use unsupported `opf:title-type` for epub2.
+ + Include "landmarks" section in nav document for epub3 (#1757).
+ + Removed playOrder from navpoint elements in ncx file (#1760).
+ These aren't required, and they make manual modification of epubs
+ difficult.
+ + Extract title even from structured title.
+ + Don't include nav node in spine unless `--toc` was requested.
+ Previously we included it in the spine with `linear="no"`, leading
+ to odd results in some readers (#1593).
+ + Fixed absolute URI detection (#1672).
+ + Correctly resolve relative URIs (#1671).
+ + Use regular page template for `nav.xhtml`, including doctype (#1759).
+
+ * Docx writer:
+
+ + Put docx table captions above tables (#1641, Nikolay Yakimov).
+ + Get the page width from the reference docx file, and use
+ it to scale images that are too large to fit (Grégory Bataille).
+ + Partial fix for #1607 (Nikolay Yakimov). International heading styles
+ are inferred based on `<w:name val="heading #">` fallback, if there
+ are no en-US "Heading#" styles
+ + Look in user data dir for archive `reference.docx`.
+ + Renumber header and footer relationships to avoid collisions (Jesse
+ Rosenthal). We previously took the old relationship names of the
+ headers and footer in secptr. That led to collisions. We now make
+ a map of availabl names in the relationships file, and then rename
+ in secptr.
+
+ * ConTeXt writer:
+
+ + Add function toLabel (Mark Szepieniec).
+ This function can be used to sanitize reference labels so that
+ they do not contain any of the illegal characters \#[]",{}%()|= .
+ Currently only Links have their labels sanitized, because they
+ are the only Elements that use passed labels.
+
+ * `Text.Pandoc.Shared`:
+
+ + Moved import of `toChunks` outside of CPP conditional (#1590).
+ + Fix `inDirectory` to reset to the original directory in case
+ an exception occurs (Freiric Barral).
+
+ * Templates:
+
+ + LaTeX template: load polyglossia before bibtex (jgm/pandoc-templates#70).
+ Thanks to bluebirch.
+ + LaTeX template: Added `\VerbatimFootnotes` if there is verbatim in notes
+ (#1616).
+ + LaTeX template: Add shorthands=off to babel options (#1648).
+ + EPUB, EPUB3 templates: Added `id="cover"` to body of cover page.
+ This aids styling, making it possible for example to set 0 margins
+ on the title page (#1758).
+ + EPUB, EPUB3 templates: Handle structured metadata on titlepage.
+ Previously we just expected 'title', 'subtitle', 'author', 'date'.
+ Now we still support those, but also support the format recommended
+ for epub metadata in the pandoc README:
+
+ ---
+ title:
+ - type: main
+ text: My Book
+ - type: subtitle
+ text: An investigation of metadata
+ creator:
+ - role: author
+ text: John Smith
+ - role: editor
+ text: Sarah Jones
+ identifier:
+ - scheme: DOI
+ text: doi:10.234234.234/33
+ publisher: My Press
+ rights: (c) 2007 John Smith, CC BY-NC
+ ...
+
+ * `Text.Pandoc.Templates.getDefaultTemplate`:
+ don't fail when called with "fb2" (#1660).
+
+ * `Text.Pandoc.Parsing`:
+
+ + Fixed `inlineMath` so it handles `\text{..}` containing `$`.
+ For example: `$x = \text{the $n$th root of $y$}` (#1677).
+ + Change `parseFromString` to fail if not all input is consumed.
+ (Matthew Pickering)
+ + Moved `addWarning` from Markdown reader to `Parsing`, so it can be
+ used by more readers (API change, Daniel Bergey).
+
+ * `Text.Pandoc.Pretty`:
+
+ + Improve performance of `realLength` (Matthew Pickering).
+ + Make CR + BLANKLINE = BLANKLINE. This fixes an extra blank line we
+ were getting at the end of markdown fragments (as well as rst, org,
+ etc.) (#1705).
+
+ * `Text.Pandoc.MIME`:
+
+ + Add mime type for WebVTT (Jason Ronallo).
+ + Changed mime type for `otf` to `application/vnd.ms-opentype` (#1761).
+ This is needed for epub3 validation.
+
+ * `Text.Pandoc.MediaBag`:
+
+ + Fix Windows specific path problems (#1597).
+
+ * `Text.Pandoc.Shared`:
+
+ + Make `collapseFilePath` OS-agnostic (Matthew Pickering).
+
+ * Link the test suite using `-threaded`.
+ This allows the test suite to be run using `+RTS -N`.
+
+ * Added `network` dependency under `network-uri` flag in test section.
+
+ * Give better error messages when someone tries to convert from
+ pdf, doc, odt (#1683).
+
+ * Added `track` to list of tags treated by `--self-contained` (#1664).
+
pandoc (1.13.1)
* Fixed `--self-contained` with Windows paths (#1558).
@@ -3634,7 +4783,7 @@ pandoc (1.9)
These constructions are now supported now by `rst2latex.py`.
- * Github syntax for fenced code blocks is supported in pandoc's
+ * GitHub syntax for fenced code blocks is supported in pandoc's
markdown. You can now write
```ruby
diff --git a/data/docx/[Content_Types].xml b/data/docx/[Content_Types].xml
new file mode 100644
index 000000000..9c5756aed
--- /dev/null
+++ b/data/docx/[Content_Types].xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="xml" ContentType="application/xml" /><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" /><Override PartName="/word/webSettings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.webSettings+xml" /><Override PartName="/word/numbering.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" /><Override PartName="/word/settings.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" /><Override PartName="/word/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml" /><Override PartName="/word/fontTable.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" /><Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" /><Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" /><Override PartName="/word/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" /><Override PartName="/word/document.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml" /><Override PartName="/word/footnotes.xml" ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" /></Types>
diff --git a/data/docx/_rels/.rels b/data/docx/_rels/.rels
new file mode 100644
index 000000000..44e5daa3d
--- /dev/null
+++ b/data/docx/_rels/.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="word/document.xml" /><Relationship Id="rId4" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml" /><Relationship Id="rId3" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml" /></Relationships> \ No newline at end of file
diff --git a/data/docx/docProps/app.xml b/data/docx/docProps/app.xml
new file mode 100644
index 000000000..1764f14d7
--- /dev/null
+++ b/data/docx/docProps/app.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes">
+ <Words>83</Words>
+ <SharedDoc>false</SharedDoc>
+ <HyperlinksChanged>false</HyperlinksChanged>
+ <Lines>12</Lines>
+ <AppVersion>12.0000</AppVersion>
+ <LinksUpToDate>false</LinksUpToDate>
+ <Application>Microsoft Word 12.0.0</Application>
+ <CharactersWithSpaces>583</CharactersWithSpaces>
+ <Template>Normal.dotm</Template>
+ <DocSecurity>0</DocSecurity>
+ <TotalTime>6</TotalTime>
+ <ScaleCrop>false</ScaleCrop>
+ <Characters>475</Characters>
+ <Paragraphs>8</Paragraphs>
+ <Pages>1</Pages>
+</Properties> \ No newline at end of file
diff --git a/data/docx/docProps/core.xml b/data/docx/docProps/core.xml
new file mode 100644
index 000000000..2274766e4
--- /dev/null
+++ b/data/docx/docProps/core.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><dc:title></dc:title><dc:creator></dc:creator></cp:coreProperties> \ No newline at end of file
diff --git a/data/docx/word/_rels/document.xml.rels b/data/docx/word/_rels/document.xml.rels
new file mode 100644
index 000000000..ca0c57b63
--- /dev/null
+++ b/data/docx/word/_rels/document.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering" Id="rId1" Target="numbering.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Id="rId2" Target="styles.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings" Id="rId3" Target="settings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings" Id="rId4" Target="webSettings.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable" Id="rId5" Target="fontTable.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme" Id="rId6" Target="theme/theme1.xml" /><Relationship Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes" Id="rId7" Target="footnotes.xml" /></Relationships>
diff --git a/data/docx/word/_rels/footnotes.xml.rels b/data/docx/word/_rels/footnotes.xml.rels
new file mode 100644
index 000000000..be7e70853
--- /dev/null
+++ b/data/docx/word/_rels/footnotes.xml.rels
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships" /> \ No newline at end of file
diff --git a/data/docx/word/document.xml b/data/docx/word/document.xml
new file mode 100644
index 000000000..7199034da
--- /dev/null
+++ b/data/docx/word/document.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:document xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"><w:body><w:p><w:r><w:t xml:space="preserve">Hello world.</w:t></w:r></w:p></w:body></w:document>
diff --git a/data/docx/word/fontTable.xml b/data/docx/word/fontTable.xml
new file mode 100644
index 000000000..fce61de9c
--- /dev/null
+++ b/data/docx/word/fontTable.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:fonts xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
+&#9;<w:font w:name="Symbol">
+&#9;&#9;<w:panose1 w:val="02000500000000000000" />
+&#9;&#9;<w:charset w:val="02" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000000" w:usb1="00000000" w:usb2="00010000" w:usb3="00000000" w:csb0="80000000" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Times New Roman">
+&#9;&#9;<w:panose1 w:val="02020603050405020304" />
+&#9;&#9;<w:charset w:val="00" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000003" w:usb1="00000000" w:usb2="00000000" w:usb3="00000000" w:csb0="00000001" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Courier New">
+&#9;&#9;<w:panose1 w:val="02070309020205020404" />
+&#9;&#9;<w:charset w:val="00" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000003" w:usb1="00000000" w:usb2="00000000" w:usb3="00000000" w:csb0="00000001" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Wingdings">
+&#9;&#9;<w:panose1 w:val="05020102010804080708" />
+&#9;&#9;<w:charset w:val="02" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000000" w:usb1="00000000" w:usb2="00010000" w:usb3="00000000" w:csb0="80000000" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Cambria">
+&#9;&#9;<w:panose1 w:val="02040503050406030204" />
+&#9;&#9;<w:charset w:val="00" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000003" w:usb1="00000000" w:usb2="00000000" w:usb3="00000000" w:csb0="00000001" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Calibri">
+&#9;&#9;<w:panose1 w:val="020F0502020204030204" />
+&#9;&#9;<w:charset w:val="00" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000003" w:usb1="00000000" w:usb2="00000000" w:usb3="00000000" w:csb0="00000001" w:csb1="00000000" />
+&#9;</w:font>
+&#9;<w:font w:name="Arial">
+&#9;&#9;<w:panose1 w:val="020B0604020202020204" />
+&#9;&#9;<w:charset w:val="00" />
+&#9;&#9;<w:family w:val="auto" />
+&#9;&#9;<w:pitch w:val="variable" />
+&#9;&#9;<w:sig w:usb0="00000003" w:usb1="00000000" w:usb2="00000000" w:usb3="00000000" w:csb0="00000001" w:csb1="00000000" />
+&#9;</w:font>
+</w:fonts> \ No newline at end of file
diff --git a/data/docx/word/footnotes.xml b/data/docx/word/footnotes.xml
new file mode 100644
index 000000000..db82d9462
--- /dev/null
+++ b/data/docx/word/footnotes.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<w:footnotes xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
+xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
+xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
+xmlns:o="urn:schemas-microsoft-com:office:office"
+xmlns:v="urn:schemas-microsoft-com:vml"
+xmlns:w10="urn:schemas-microsoft-com:office:word"
+xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
+xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture"
+xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing">
+
+ <w:footnote w:type="continuationSeparator" w:id="0">
+ <w:p>
+ <w:r>
+ <w:continuationSeparator />
+ </w:r>
+ </w:p>
+ </w:footnote>
+ <w:footnote w:type="separator" w:id="-1">
+ <w:p>
+ <w:r>
+ <w:separator />
+ </w:r>
+ </w:p>
+ </w:footnote>
+</w:footnotes>
diff --git a/data/docx/word/numbering.xml b/data/docx/word/numbering.xml
new file mode 100644
index 000000000..b9e91371b
--- /dev/null
+++ b/data/docx/word/numbering.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:numbering xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"><w:abstractNum w:abstractNumId="0"><w:nsid w:val="e17f69ba" /><w:multiLevelType w:val="multilevel" /><w:lvl w:ilvl="0"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="0" /></w:tabs><w:ind w:left="480" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="1"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="720" /></w:tabs><w:ind w:left="1200" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="2"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="1440" /></w:tabs><w:ind w:left="1920" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="3"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2160" /></w:tabs><w:ind w:left="2640" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="4"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="2880" /></w:tabs><w:ind w:left="3360" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="5"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="3600" /></w:tabs><w:ind w:left="4080" w:hanging="480" /></w:pPr></w:lvl><w:lvl w:ilvl="6"><w:numFmt w:val="bullet" /><w:lvlText w:val=" " /><w:lvlJc w:val="left" /><w:pPr><w:tabs><w:tab w:val="num" w:pos="4320" /></w:tabs><w:ind w:left="4800" w:hanging="480" /></w:pPr></w:lvl></w:abstractNum><w:num w:numId="1"><w:abstractNumId w:val="0" /></w:num></w:numbering> \ No newline at end of file
diff --git a/data/docx/word/settings.xml b/data/docx/word/settings.xml
new file mode 100644
index 000000000..425e6f7b5
--- /dev/null
+++ b/data/docx/word/settings.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:settings xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:sl="http://schemas.openxmlformats.org/schemaLibrary/2006/main">
+ <w:zoom w:percent="90" />
+ <w:embedSystemFonts />
+ <w:proofState w:spelling="clean" w:grammar="clean" />
+ <w:stylePaneFormatFilter w:val="0004" />
+ <w:footnotePr>
+ <w:footnote w:id="-1" />
+ <w:footnote w:id="0" />
+ </w:footnotePr>
+ <w:doNotTrackMoves />
+ <w:defaultTabStop w:val="720" />
+ <w:drawingGridHorizontalSpacing w:val="360" />
+ <w:drawingGridVerticalSpacing w:val="360" />
+ <w:displayHorizontalDrawingGridEvery w:val="0" />
+ <w:displayVerticalDrawingGridEvery w:val="0" />
+ <w:characterSpacingControl w:val="doNotCompress" />
+ <w:savePreviewPicture />
+ <w:rsids>
+ <w:rsidRoot w:val="00590D07" />
+ <w:rsid w:val="00011C8B" />
+ <w:rsid w:val="004E29B3" />
+ <w:rsid w:val="00590D07" />
+ <w:rsid w:val="00784D58" />
+ <w:rsid w:val="008D6863" />
+ <w:rsid w:val="00B86B75" />
+ <w:rsid w:val="00BC48D5" />
+ <w:rsid w:val="00C36279" />
+ <w:rsid w:val="00E315A3" />
+ </w:rsids>
+ <m:mathPr>
+ <m:mathFont m:val="Lucida Grande" />
+ <m:brkBin m:val="before" />
+ <m:brkBinSub m:val="--" />
+ <m:smallFrac m:val="false" />
+ <m:dispDef m:val="false" />
+ <m:lMargin m:val="0" />
+ <m:rMargin m:val="0" />
+ <m:wrapRight />
+ <m:intLim m:val="subSup" />
+ <m:naryLim m:val="subSup" />
+ </m:mathPr>
+ <w:themeFontLang w:val="en-US" />
+ <w:clrSchemeMapping w:bg1="light1" w:t1="dark1" w:bg2="light2" w:t2="dark2" w:accent1="accent1" w:accent2="accent2" w:accent3="accent3" w:accent4="accent4" w:accent5="accent5" w:accent6="accent6" w:hyperlink="hyperlink" w:followedHyperlink="followedHyperlink" />
+ <w:decimalSymbol w:val="." />
+ <w:listSeparator w:val="," />
+</w:settings>
diff --git a/data/docx/word/styles.xml b/data/docx/word/styles.xml
new file mode 100644
index 000000000..d19c4c7fb
--- /dev/null
+++ b/data/docx/word/styles.xml
@@ -0,0 +1,396 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<w:styles xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
+ <w:docDefaults>
+ <w:rPrDefault>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="minorHAnsi" w:eastAsiaTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi" w:cstheme="minorBidi" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ <w:lang w:val="en-US" w:eastAsia="en-US" w:bidi="ar-SA" />
+ </w:rPr>
+ </w:rPrDefault>
+ <w:pPrDefault>
+ <w:pPr>
+ <w:spacing w:after="200" />
+ </w:pPr>
+ </w:pPrDefault>
+ </w:docDefaults>
+ <w:latentStyles w:defLockedState="0" w:defUIPriority="0" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="276" />
+ <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
+ <w:name w:val="Normal" />
+ <w:qFormat />
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="BodyText">
+ <w:name w:val="Body Text" />
+ <w:basedOn w:val="Normal" />
+ <w:link w:val="BodyTextChar" />
+ <w:pPr>
+ <w:spacing w:before="180" w:after="180" />
+ </w:pPr>
+ <w:qFormat />
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="FirstParagraph">
+ <w:name w:val="First Paragraph" />
+ <w:basedOn w:val="BodyText" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="Compact">
+ <w:name w:val="Compact" />
+ <w:basedOn w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:spacing w:before="36" w:after="36" />
+ </w:pPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Title">
+ <w:name w:val="Title" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="480" w:after="240" />
+ <w:jc w:val="center" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b />
+ <w:bCs />
+ <w:color w:val="345A8A" w:themeColor="accent1" w:themeShade="B5" />
+ <w:sz w:val="36" />
+ <w:szCs w:val="36" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Subtitle">
+ <w:name w:val="Subtitle" />
+ <w:basedOn w:val="Title" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="240" w:after="240" />
+ <w:jc w:val="center" />
+ </w:pPr>
+ <w:rPr>
+ <w:sz w:val="30" />
+ <w:szCs w:val="30" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="Author">
+ <w:name w:val="Author" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:jc w:val="center" />
+ </w:pPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Date">
+ <w:name w:val="Date" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:jc w:val="center" />
+ </w:pPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="Abstract">
+ <w:name w:val="Abstract" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="300" w:after="300" />
+ </w:pPr>
+ <w:rPr>
+ <w:sz w:val="20" />
+ <w:szCs w:val="20" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Bibliography">
+ <w:name w:val="Bibliography" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="Bibliography" />
+ <w:qFormat />
+ <w:pPr />
+ <w:rPr />
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading1">
+ <w:name w:val="Heading 1" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="480" w:after="0" />
+ <w:outlineLvl w:val="0" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b />
+ <w:bCs />
+ <w:color w:val="345A8A" w:themeColor="accent1" w:themeShade="B5" />
+ <w:sz w:val="32" />
+ <w:szCs w:val="32" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading2">
+ <w:name w:val="Heading 2" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="1" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b />
+ <w:bCs />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="32" />
+ <w:szCs w:val="32" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading3">
+ <w:name w:val="Heading 3" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="2" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b />
+ <w:bCs />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="28" />
+ <w:szCs w:val="28" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading4">
+ <w:name w:val="Heading 4" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="3" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b />
+ <w:bCs />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading5">
+ <w:name w:val="Heading 5" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="4" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:i />
+ <w:iCs />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Heading6">
+ <w:name w:val="Heading 6" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:before="200" w:after="0" />
+ <w:outlineLvl w:val="5" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ <w:sz w:val="24" />
+ <w:szCs w:val="24" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="BlockText">
+ <w:name w:val="Block Text" />
+ <w:basedOn w:val="BodyText" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:spacing w:before="100" w:after="100" />
+ <w:ind w:firstLine="0" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:bCs />
+ <w:sz w:val="20" />
+ <w:szCs w:val="20" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="FootnoteText">
+ <w:name w:val="Footnote Text" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="FootnoteText" />
+ <w:uiPriority w:val="9" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ </w:style>
+ <w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
+ <w:name w:val="Default Paragraph Font" />
+ <w:semiHidden />
+ <w:unhideWhenUsed />
+ </w:style>
+ <w:style w:type="table" w:default="1" w:styleId="TableNormal">
+ <w:name w:val="Normal Table" />
+ <w:semiHidden />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:tblPr>
+ <w:tblInd w:w="0" w:type="dxa" />
+ <w:tblCellMar>
+ <w:top w:w="0" w:type="dxa" />
+ <w:left w:w="108" w:type="dxa" />
+ <w:bottom w:w="0" w:type="dxa" />
+ <w:right w:w="108" w:type="dxa" />
+ </w:tblCellMar>
+ </w:tblPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="DefinitionTerm">
+ <w:name w:val="Definition Term" />
+ <w:basedOn w:val="Normal" />
+ <w:next w:val="Definition" />
+ <w:pPr>
+ <w:keepNext />
+ <w:keepLines />
+ <w:spacing w:after="0" />
+ </w:pPr>
+ <w:rPr>
+ <w:b />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="Definition">
+ <w:name w:val="Definition" />
+ <w:basedOn w:val="Normal" />
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="Caption">
+ <w:name w:val="Caption" />
+ <w:basedOn w:val="Normal" />
+ <w:link w:val="BodyTextChar" />
+ <w:pPr>
+ <w:spacing w:before="0" w:after="120" />
+ </w:pPr>
+ <w:rPr>
+ <w:i />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="TableCaption">
+ <w:name w:val="Table Caption" />
+ <w:basedOn w:val="Caption" />
+ <w:pPr>
+ <w:keepNext />
+ </w:pPr>
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="ImageCaption">
+ <w:name w:val="Image Caption" />
+ <w:basedOn w:val="Caption" />
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="Figure">
+ <w:name w:val="Figure" />
+ <w:basedOn w:val="Normal" />
+ </w:style>
+ <w:style w:type="paragraph" w:customStyle="1" w:styleId="FigureWithCaption">
+ <w:name w:val="Figure with Caption" />
+ <w:basedOn w:val="Figure" />
+ <w:pPr>
+ <w:keepNext />
+ </w:pPr>
+ </w:style>
+ <w:style w:type="character" w:customStyle="1" w:styleId="BodyTextChar">
+ <w:name w:val="Body Text Char" />
+ <w:basedOn w:val="DefaultParagraphFont" />
+ <w:link w:val="BodyText" />
+ </w:style>
+ <w:style w:type="character" w:customStyle="1" w:styleId="VerbatimChar">
+ <w:name w:val="Verbatim Char" />
+ <w:basedOn w:val="BodyTextChar" />
+ <w:rPr>
+ <w:rFonts w:ascii="Consolas" w:hAnsi="Consolas" />
+ <w:sz w:val="22" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="character" w:styleId="FootnoteReference">
+ <w:name w:val="Footnote Reference" />
+ <w:basedOn w:val="BodyTextChar" />
+ <w:rPr>
+ <w:vertAlign w:val="superscript" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="character" w:styleId="Hyperlink">
+ <w:name w:val="Hyperlink" />
+ <w:basedOn w:val="BodyTextChar" />
+ <w:rPr>
+ <w:color w:val="4F81BD" w:themeColor="accent1" />
+ </w:rPr>
+ </w:style>
+ <w:style w:type="paragraph" w:styleId="TOCHeading">
+ <w:name w:val="TOC Heading" />
+ <w:basedOn w:val="Heading1" />
+ <w:next w:val="BodyText" />
+ <w:uiPriority w:val="39" />
+ <w:unhideWhenUsed />
+ <w:qFormat />
+ <w:pPr>
+ <w:spacing w:before="240" w:line="259" w:lineRule="auto" />
+ <w:outlineLvl w:val="9" />
+ </w:pPr>
+ <w:rPr>
+ <w:rFonts w:asciiTheme="majorHAnsi" w:eastAsiaTheme="majorEastAsia" w:hAnsiTheme="majorHAnsi" w:cstheme="majorBidi" />
+ <w:b w:val="0" />
+ <w:bCs w:val="0" />
+ <w:color w:val="365F91" w:themeColor="accent1"
+ w:themeShade="BF" />
+ </w:rPr>
+ </w:style>
+</w:styles>
diff --git a/data/docx/word/theme/theme1.xml b/data/docx/word/theme/theme1.xml
new file mode 100644
index 000000000..a6f7240c4
--- /dev/null
+++ b/data/docx/word/theme/theme1.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme"><a:themeElements><a:clrScheme name="Office"><a:dk1><a:sysClr val="windowText" lastClr="000000" /></a:dk1><a:lt1><a:sysClr val="window" lastClr="FFFFFF" /></a:lt1><a:dk2><a:srgbClr val="1F497D" /></a:dk2><a:lt2><a:srgbClr val="EEECE1" /></a:lt2><a:accent1><a:srgbClr val="4F81BD" /></a:accent1><a:accent2><a:srgbClr val="C0504D" /></a:accent2><a:accent3><a:srgbClr val="9BBB59" /></a:accent3><a:accent4><a:srgbClr val="8064A2" /></a:accent4><a:accent5><a:srgbClr val="4BACC6" /></a:accent5><a:accent6><a:srgbClr val="F79646" /></a:accent6><a:hlink><a:srgbClr val="0000FF" /></a:hlink><a:folHlink><a:srgbClr val="800080" /></a:folHlink></a:clrScheme><a:fontScheme name="Office"><a:majorFont><a:latin typeface="Calibri" /><a:ea typeface="" /><a:cs typeface="" /><a:font script="Jpan" typeface="MS ゴシック" /><a:font script="Hang" typeface="맑은 고딕" /><a:font script="Hans" typeface="宋体" /><a:font script="Hant" typeface="新細明體" /><a:font script="Arab" typeface="Times New Roman" /><a:font script="Hebr" typeface="Times New Roman" /><a:font script="Thai" typeface="Angsana New" /><a:font script="Ethi" typeface="Nyala" /><a:font script="Beng" typeface="Vrinda" /><a:font script="Gujr" typeface="Shruti" /><a:font script="Khmr" typeface="MoolBoran" /><a:font script="Knda" typeface="Tunga" /><a:font script="Guru" typeface="Raavi" /><a:font script="Cans" typeface="Euphemia" /><a:font script="Cher" typeface="Plantagenet Cherokee" /><a:font script="Yiii" typeface="Microsoft Yi Baiti" /><a:font script="Tibt" typeface="Microsoft Himalaya" /><a:font script="Thaa" typeface="MV Boli" /><a:font script="Deva" typeface="Mangal" /><a:font script="Telu" typeface="Gautami" /><a:font script="Taml" typeface="Latha" /><a:font script="Syrc" typeface="Estrangelo Edessa" /><a:font script="Orya" typeface="Kalinga" /><a:font script="Mlym" typeface="Kartika" /><a:font script="Laoo" typeface="DokChampa" /><a:font script="Sinh" typeface="Iskoola Pota" /><a:font script="Mong" typeface="Mongolian Baiti" /><a:font script="Viet" typeface="Times New Roman" /><a:font script="Uigh" typeface="Microsoft Uighur" /></a:majorFont><a:minorFont><a:latin typeface="Cambria" /><a:ea typeface="" /><a:cs typeface="" /><a:font script="Jpan" typeface="MS 明朝" /><a:font script="Hang" typeface="맑은 고딕" /><a:font script="Hans" typeface="宋体" /><a:font script="Hant" typeface="新細明體" /><a:font script="Arab" typeface="Arial" /><a:font script="Hebr" typeface="Arial" /><a:font script="Thai" typeface="Cordia New" /><a:font script="Ethi" typeface="Nyala" /><a:font script="Beng" typeface="Vrinda" /><a:font script="Gujr" typeface="Shruti" /><a:font script="Khmr" typeface="DaunPenh" /><a:font script="Knda" typeface="Tunga" /><a:font script="Guru" typeface="Raavi" /><a:font script="Cans" typeface="Euphemia" /><a:font script="Cher" typeface="Plantagenet Cherokee" /><a:font script="Yiii" typeface="Microsoft Yi Baiti" /><a:font script="Tibt" typeface="Microsoft Himalaya" /><a:font script="Thaa" typeface="MV Boli" /><a:font script="Deva" typeface="Mangal" /><a:font script="Telu" typeface="Gautami" /><a:font script="Taml" typeface="Latha" /><a:font script="Syrc" typeface="Estrangelo Edessa" /><a:font script="Orya" typeface="Kalinga" /><a:font script="Mlym" typeface="Kartika" /><a:font script="Laoo" typeface="DokChampa" /><a:font script="Sinh" typeface="Iskoola Pota" /><a:font script="Mong" typeface="Mongolian Baiti" /><a:font script="Viet" typeface="Arial" /><a:font script="Uigh" typeface="Microsoft Uighur" /></a:minorFont></a:fontScheme><a:fmtScheme name="Office"><a:fillStyleLst><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000" /><a:satMod val="300000" /></a:schemeClr></a:gs><a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000" /><a:satMod val="300000" /></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000" /><a:satMod val="350000" /></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="1" /></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000" /><a:shade val="100000" /><a:satMod val="130000" /></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000" /><a:shade val="100000" /><a:satMod val="350000" /></a:schemeClr></a:gs></a:gsLst><a:lin ang="16200000" scaled="0" /></a:gradFill></a:fillStyleLst><a:lnStyleLst><a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"><a:shade val="95000" /><a:satMod val="105000" /></a:schemeClr></a:solidFill><a:prstDash val="solid" /></a:ln><a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:prstDash val="solid" /></a:ln><a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:prstDash val="solid" /></a:ln></a:lnStyleLst><a:effectStyleLst><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="38000" /></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000" /></a:srgbClr></a:outerShdw></a:effectLst></a:effectStyle><a:effectStyle><a:effectLst><a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000" /></a:srgbClr></a:outerShdw></a:effectLst><a:scene3d><a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0" /></a:camera><a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000" /></a:lightRig></a:scene3d><a:sp3d><a:bevelT w="63500" h="25400" /></a:sp3d></a:effectStyle></a:effectStyleLst><a:bgFillStyleLst><a:solidFill><a:schemeClr val="phClr" /></a:solidFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000" /><a:satMod val="350000" /></a:schemeClr></a:gs><a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000" /><a:shade val="99000" /><a:satMod val="350000" /></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000" /><a:satMod val="255000" /></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000" /></a:path></a:gradFill><a:gradFill rotWithShape="1"><a:gsLst><a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000" /><a:satMod val="300000" /></a:schemeClr></a:gs><a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000" /><a:satMod val="200000" /></a:schemeClr></a:gs></a:gsLst><a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000" /></a:path></a:gradFill></a:bgFillStyleLst></a:fmtScheme></a:themeElements><a:objectDefaults><a:spDef><a:spPr /><a:bodyPr /><a:lstStyle /><a:style><a:lnRef idx="1"><a:schemeClr val="accent1" /></a:lnRef><a:fillRef idx="3"><a:schemeClr val="accent1" /></a:fillRef><a:effectRef idx="2"><a:schemeClr val="accent1" /></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1" /></a:fontRef></a:style></a:spDef><a:lnDef><a:spPr /><a:bodyPr /><a:lstStyle /><a:style><a:lnRef idx="2"><a:schemeClr val="accent1" /></a:lnRef><a:fillRef idx="0"><a:schemeClr val="accent1" /></a:fillRef><a:effectRef idx="1"><a:schemeClr val="accent1" /></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="tx1" /></a:fontRef></a:style></a:lnDef></a:objectDefaults><a:extraClrSchemeLst /></a:theme> \ No newline at end of file
diff --git a/data/docx/word/webSettings.xml b/data/docx/word/webSettings.xml
new file mode 100644
index 000000000..570ca8e1a
--- /dev/null
+++ b/data/docx/word/webSettings.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ns0:webSettings xmlns:ns0="http://schemas.openxmlformats.org/wordprocessingml/2006/main">
+ <ns0:allowPNG />
+ <ns0:doNotSaveAsSingleFile />
+</ns0:webSettings> \ No newline at end of file
diff --git a/data/dzslides/template.html b/data/dzslides/template.html
index f2fb64b38..56ef8963e 100644
--- a/data/dzslides/template.html
+++ b/data/dzslides/template.html
@@ -23,14 +23,23 @@
<li>Item 1
<li>Item 2
<li>Item 3
+ <ul class="incremental">
+ <li> Item 3.1
+ <li> Item 3.2
+ </ul>
</ul>
- <details>Some notes. They are only visible using onstage shell.</details>
+ <div role="note">Some notes. They are only visible using onstage shell.</div>
</section>
<section>
- <q>
+ <blockquote>
Who's brave enough to fly into something we all keep calling a death sphere?
- </q>
+ </blockquote>
+ <details>
+ <p>In the onstage shell, notes scroll rather than overflow:</p>
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla ac dui eu est feugiat lacinia sit amet nec leo. Mauris eu ipsum leo. Nulla mi odio, cursus sed sollicitudin non, fringilla id magna. Suspendisse sit amet posuere elit. Maecenas iaculis, turpis a placerat imperdiet, libero lorem feugiat nisi, nec tincidunt diam nibh sit amet massa. Vestibulum quis adipiscing tellus. Maecenas sollicitudin sodales pulvinar. Donec dui ipsum, bibendum facilisis consequat interdum, tempus ut mauris. Aliquam ut dolor nec odio scelerisque bibendum quis in neque. Aliquam dui dui, pulvinar quis fermentum quis, gravida eu augue. Nunc tristique dolor a urna pulvinar bibendum. Curabitur mollis cursus neque, in scelerisque metus porta non. Donec tempor enim in nibh vestibulum et convallis nisi malesuada. Duis ut lectus sed metus venenatis porttitor id pharetra quam. Suspendisse sapien turpis, ornare in molestie et, gravida eget turpis.
+ </p>
+ </details>
</section>
<section>
@@ -42,7 +51,7 @@
<img src="http://placekitten.com/g/800/600">
<figcaption>An image</figcaption>
</figure>
- <details>Kittens are so cute!</details>
+ <div role="note">Kittens are so cute!</div>
</section>
<section>
@@ -63,14 +72,28 @@
<link href='http://fonts.googleapis.com/css?family=Oswald' rel='stylesheet'>
<style>
- html { background-color: black; }
- body { background-color: white; border-radius: 12px}
+ html, .view body { background-color: black; counter-reset: slideidx; }
+ body, .view section { background-color: white; border-radius: 12px }
/* A section is a slide. It's size is 800x600, and this will never change */
- section {
+ section, .view head > title {
/* The font from Google */
font-family: 'Oswald', arial, serif;
font-size: 30px;
}
+
+ .view section:after {
+ counter-increment: slideidx;
+ content: counter(slideidx, decimal-leading-zero);
+ position: absolute; bottom: -80px; right: 100px;
+ color: white;
+ }
+
+ .view head > title {
+ color: white;
+ text-align: center;
+ margin: 1em 0 1em 0;
+ }
+
h1, h2 {
margin-top: 200px;
text-align: center;
@@ -83,26 +106,41 @@
ul {
margin: 50px 200px;
}
+ li > ul {
+ margin: 15px 50px;
+ }
p {
margin: 75px;
font-size: 50px;
}
- q {
- display: block;
- width: 100%;
+ blockquote {
height: 100%;
background-color: black;
color: white;
font-size: 60px;
padding: 50px;
}
+ blockquote:before {
+ content: open-quote;
+ }
+ blockquote:after {
+ content: close-quote;
+ }
/* Figures are displayed full-page, with the caption
on top of the image/video */
figure {
background-color: black;
+ width: 100%;
+ height: 100%;
+ }
+ figure > * {
+ position: absolute;
+ }
+ figure > img, figure > video {
+ width: 100%; height: 100%;
}
figcaption {
margin: 70px;
@@ -125,10 +163,20 @@
https://developer.mozilla.org/en/CSS/CSS_transitions
How to use CSS3 Transitions: */
section {
- -moz-transition: left 400ms linear 0s;
- -webkit-transition: left 400ms linear 0s;
- -ms-transition: left 400ms linear 0s;
- transition: left 400ms linear 0s;
+ -moz-transition: left 400ms linear 0s;
+ -webkit-transition: left 400ms linear 0s;
+ -ms-transition: left 400ms linear 0s;
+ transition: left 400ms linear 0s;
+ }
+ .view section {
+ -moz-transition: none;
+ -webkit-transition: none;
+ -ms-transition: none;
+ transition: none;
+ }
+
+ .view section[aria-selected] {
+ border: 5px red solid;
}
/* Before */
@@ -176,21 +224,50 @@
<!-- Default Style -->
<style>
* { margin: 0; padding: 0; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; }
- details { display: none; }
+ [role="note"] { display: none; }
body {
width: 800px; height: 600px;
margin-left: -400px; margin-top: -300px;
position: absolute; top: 50%; left: 50%;
overflow: hidden;
+ display: none;
}
+ .view body {
+ position: static;
+ margin: 0; padding: 0;
+ width: 100%; height: 100%;
+ display: inline-block;
+ overflow: visible; overflow-x: hidden;
+ /* undo Dz.onresize */
+ transform: none !important;
+ -moz-transform: none !important;
+ -webkit-transform: none !important;
+ -o-transform: none !important;
+ -ms-transform: none !important;
+ }
+ .view head, .view head > title { display: block }
section {
position: absolute;
pointer-events: none;
width: 100%; height: 100%;
}
+ .view section {
+ pointer-events: auto;
+ position: static;
+ width: 800px; height: 600px;
+ margin: -150px -200px;
+ float: left;
+
+ transform: scale(.4);
+ -moz-transform: scale(.4);
+ -webkit-transform: scale(.4);
+ -o-transform: scale(.4);
+ -ms-transform: scale(.4);
+ }
+ .view section > * { pointer-events: none; }
section[aria-selected] { pointer-events: auto; }
html { overflow: hidden; }
- body { display: none; }
+ html.view { overflow: visible; }
body.loaded { display: block; }
.incremental {visibility: hidden; }
.incremental[active] {visibility: visible; }
@@ -202,15 +279,8 @@
-ms-transition: width 400ms linear 0s;
transition: width 400ms linear 0s;
}
- figure {
- width: 100%;
- height: 100%;
- }
- figure > * {
- position: absolute;
- }
- figure > img, figure > video {
- width: 100%; height: 100%;
+ .view #progress-bar {
+ display: none;
}
</style>
@@ -219,6 +289,7 @@
remoteWindows: [],
idx: -1,
step: 0,
+ html: null,
slides: null,
progressBar : null,
params: {
@@ -228,14 +299,16 @@
Dz.init = function() {
document.body.className = "loaded";
- this.slides = $$("body > section");
+ this.slides = Array.prototype.slice.call($$("body > section"));
this.progressBar = $("#progress-bar");
+ this.html = document.body.parentNode;
this.setupParams();
this.onhashchange();
this.setupTouchEvents();
this.onresize();
+ this.setupView();
}
-
+
Dz.setupParams = function() {
var p = window.location.search.substr(1).split('&');
p.forEach(function(e, i, a) {
@@ -285,6 +358,10 @@
aEvent.preventDefault();
this.goFullscreen();
}
+ if (aEvent.keyCode == 79) { // o
+ aEvent.preventDefault();
+ this.toggleView();
+ }
}
/* Touch Events */
@@ -318,6 +395,16 @@
}
}
+ Dz.setupView = function() {
+ document.body.addEventListener("click", function ( e ) {
+ if (!Dz.html.classList.contains("view")) return;
+ if (!e.target || e.target.nodeName != "SECTION") return;
+
+ Dz.html.classList.remove("view");
+ Dz.setCursor(Dz.slides.indexOf(e.target) + 1);
+ }, false);
+ }
+
/* Adapt the size of the slides to the window */
Dz.onresize = function() {
@@ -334,9 +421,9 @@
}
- Dz.getDetails = function(aIdx) {
+ Dz.getNotes = function(aIdx) {
var s = $("section:nth-of-type(" + aIdx + ")");
- var d = s.$("details");
+ var d = s.$("[role='note']");
return d ? d.innerHTML : "";
}
@@ -365,7 +452,7 @@
if (argv[0] === "GET_CURSOR" && argc === 1)
this.postMsg(win, "CURSOR", this.idx + "." + this.step);
if (argv[0] === "GET_NOTES" && argc === 1)
- this.postMsg(win, "NOTES", this.getDetails(this.idx));
+ this.postMsg(win, "NOTES", this.getNotes(this.idx));
}
Dz.toggleContent = function() {
@@ -449,6 +536,14 @@
this.setCursor(lastIdx, lastStep);
}
+ Dz.toggleView = function() {
+ this.html.classList.toggle("view");
+
+ if (this.html.classList.contains("view")) {
+ $("section[aria-selected]").scrollIntoView(true);
+ }
+ }
+
Dz.setSlide = function(aIdx) {
this.idx = aIdx;
var old = $("section[aria-selected]");
@@ -462,6 +557,9 @@
}
if (next) {
next.setAttribute("aria-selected", "true");
+ if (this.html.classList.contains("view")) {
+ next.scrollIntoView();
+ }
var video = next.$("video");
if (video && !!+this.params.autoplay) {
video.play();
diff --git a/data/epub.css b/data/epub.css
index 93153d62a..1ea24680d 100644
--- a/data/epub.css
+++ b/data/epub.css
@@ -12,3 +12,4 @@ h2.author { }
h3.date { }
ol.toc { padding: 0; margin-left: 1em; }
ol.toc li { list-style-type: none; margin: 0; padding: 0; }
+a.footnoteRef { vertical-align: super; } \ No newline at end of file
diff --git a/data/make-reference-files.hs b/data/make-reference-files.hs
new file mode 100644
index 000000000..77e518496
--- /dev/null
+++ b/data/make-reference-files.hs
@@ -0,0 +1,27 @@
+import System.Environment
+import System.Directory
+import Codec.Archive.Zip
+import qualified Data.ByteString.Lazy as BS
+import qualified Control.Exception as E
+import System.IO.Error (isDoesNotExistError)
+import System.FilePath
+
+mkzip :: String -> IO ()
+mkzip fmt = do
+ let dir = "data" </> fmt
+ output = "data" </> "reference" <.> fmt
+ cd <- getCurrentDirectory
+ setCurrentDirectory dir
+ archive <- addFilesToArchive [OptRecursive] emptyArchive ["."]
+ setCurrentDirectory cd
+ removeIfExists output
+ BS.writeFile output $ fromArchive archive
+
+removeIfExists :: FilePath -> IO ()
+removeIfExists fileName = removeFile fileName `E.catch` handleExists
+ where handleExists e
+ | isDoesNotExistError e = return ()
+ | otherwise = E.throwIO e
+
+main :: IO ()
+main = getArgs >>= mkzip . (!!0)
diff --git a/data/odt/Configurations2/accelerator/current.xml b/data/odt/Configurations2/accelerator/current.xml
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/data/odt/Configurations2/accelerator/current.xml
diff --git a/data/odt/META-INF/manifest.xml b/data/odt/META-INF/manifest.xml
new file mode 100644
index 000000000..2796993a5
--- /dev/null
+++ b/data/odt/META-INF/manifest.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">
+ <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.text"/>
+ <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/>
+ <manifest:file-entry manifest:full-path="Thumbnails/thumbnail.png" manifest:media-type="image/png"/>
+ <manifest:file-entry manifest:full-path="manifest.rdf" manifest:media-type="application/rdf+xml"/>
+ <manifest:file-entry manifest:full-path="Configurations2/accelerator/current.xml" manifest:media-type=""/>
+ <manifest:file-entry manifest:full-path="Configurations2/" manifest:media-type="application/vnd.sun.xml.ui.configuration"/>
+ <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/>
+</manifest:manifest> \ No newline at end of file
diff --git a/data/odt/Thumbnails/thumbnail.png b/data/odt/Thumbnails/thumbnail.png
new file mode 100644
index 000000000..63de13060
--- /dev/null
+++ b/data/odt/Thumbnails/thumbnail.png
Binary files differ
diff --git a/data/odt/content.xml b/data/odt/content.xml
new file mode 100644
index 000000000..3bf335bb6
--- /dev/null
+++ b/data/odt/content.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"><office:scripts/><office:font-face-decls><style:font-face style:name="StarSymbol" svg:font-family="StarSymbol"/><style:font-face style:name="Tahoma1" svg:font-family="Tahoma"/><style:font-face style:name="Courier New" svg:font-family="&apos;Courier New&apos;" style:font-family-generic="modern" style:font-pitch="fixed"/><style:font-face style:name="Times New Roman" svg:font-family="&apos;Times New Roman&apos;" style:font-family-generic="roman" style:font-pitch="variable"/><style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable"/><style:font-face style:name="Lucida Sans Unicode" svg:font-family="&apos;Lucida Sans Unicode&apos;" style:font-family-generic="system" style:font-pitch="variable"/><style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable"/></office:font-face-decls><office:automatic-styles><style:style style:name="P1" style:family="paragraph" style:parent-style-name="Footer"><style:paragraph-properties fo:text-align="center" style:justify-single-word="false"/></style:style></office:automatic-styles><office:body><office:text><text:sequence-decls><text:sequence-decl text:display-outline-level="0" text:name="Illustration"/><text:sequence-decl text:display-outline-level="0" text:name="Table"/><text:sequence-decl text:display-outline-level="0" text:name="Text"/><text:sequence-decl text:display-outline-level="0" text:name="Drawing"/></text:sequence-decls><text:p text:style-name="Standard">Hello World!</text:p></office:text></office:body></office:document-content> \ No newline at end of file
diff --git a/data/odt/manifest.rdf b/data/odt/manifest.rdf
new file mode 100644
index 000000000..927e206bb
--- /dev/null
+++ b/data/odt/manifest.rdf
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+ <rdf:Description rdf:about="styles.xml">
+ <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#StylesFile"/>
+ </rdf:Description>
+ <rdf:Description rdf:about="">
+ <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="styles.xml"/>
+ </rdf:Description>
+ <rdf:Description rdf:about="content.xml">
+ <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/odf#ContentFile"/>
+ </rdf:Description>
+ <rdf:Description rdf:about="">
+ <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="content.xml"/>
+ </rdf:Description>
+ <rdf:Description rdf:about="">
+ <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#Document"/>
+ </rdf:Description>
+</rdf:RDF>
diff --git a/data/odt/meta.xml b/data/odt/meta.xml
new file mode 100644
index 000000000..7fdd4d98c
--- /dev/null
+++ b/data/odt/meta.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-meta
+ xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
+ xmlns:ooo="http://openoffice.org/2004/office"
+ xmlns:grddl="http://www.w3.org/2003/g/data-view#"
+ office:version="1.2">
+ <office:meta>
+ <meta:document-statistic
+ meta:table-count="0" meta:image-count="0" meta:object-count="0"
+ meta:page-count="1" meta:paragraph-count="2" meta:word-count="3"
+ meta:character-count="14"
+ meta:non-whitespace-character-count="12"/>
+ <meta:generator>Pandoc</meta:generator>
+ </office:meta>
+</office:document-meta>
diff --git a/data/odt/mimetype b/data/odt/mimetype
new file mode 100644
index 000000000..2e95b81c9
--- /dev/null
+++ b/data/odt/mimetype
@@ -0,0 +1 @@
+application/vnd.oasis.opendocument.text \ No newline at end of file
diff --git a/data/odt/settings.xml b/data/odt/settings.xml
new file mode 100644
index 000000000..20bc19d14
--- /dev/null
+++ b/data/odt/settings.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2"><office:settings><config:config-item-set config:name="ooo:view-settings"><config:config-item config:name="ViewAreaTop" config:type="int">0</config:config-item><config:config-item config:name="ViewAreaLeft" config:type="int">0</config:config-item><config:config-item config:name="ViewAreaWidth" config:type="int">21747</config:config-item><config:config-item config:name="ViewAreaHeight" config:type="int">10874</config:config-item><config:config-item config:name="ShowRedlineChanges" config:type="boolean">true</config:config-item><config:config-item config:name="InBrowseMode" config:type="boolean">false</config:config-item><config:config-item-map-indexed config:name="Views"><config:config-item-map-entry><config:config-item config:name="ViewId" config:type="string">view2</config:config-item><config:config-item config:name="ViewLeft" config:type="int">3041</config:config-item><config:config-item config:name="ViewTop" config:type="int">3041</config:config-item><config:config-item config:name="VisibleLeft" config:type="int">0</config:config-item><config:config-item config:name="VisibleTop" config:type="int">0</config:config-item><config:config-item config:name="VisibleRight" config:type="int">21745</config:config-item><config:config-item config:name="VisibleBottom" config:type="int">10873</config:config-item><config:config-item config:name="ZoomType" config:type="short">0</config:config-item><config:config-item config:name="ViewLayoutColumns" config:type="short">0</config:config-item><config:config-item config:name="ViewLayoutBookMode" config:type="boolean">false</config:config-item><config:config-item config:name="ZoomFactor" config:type="short">100</config:config-item><config:config-item config:name="IsSelectedFrame" config:type="boolean">false</config:config-item></config:config-item-map-entry></config:config-item-map-indexed></config:config-item-set><config:config-item-set config:name="ooo:configuration-settings"><config:config-item config:name="ChartAutoUpdate" config:type="boolean">true</config:config-item><config:config-item config:name="IsLabelDocument" config:type="boolean">false</config:config-item><config:config-item config:name="MathBaselineAlignment" config:type="boolean">false</config:config-item><config:config-item config:name="Rsid" config:type="int">1473719</config:config-item><config:config-item config:name="OutlineLevelYieldsNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="PrintLeftPages" config:type="boolean">true</config:config-item><config:config-item config:name="DoNotJustifyLinesWithManualBreak" config:type="boolean">false</config:config-item><config:config-item config:name="ClippedPictures" config:type="boolean">false</config:config-item><config:config-item config:name="AlignTabStopPosition" config:type="boolean">true</config:config-item><config:config-item config:name="PrintTextPlaceholder" config:type="boolean">false</config:config-item><config:config-item config:name="UseOldNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="CurrentDatabaseCommand" config:type="string"/><config:config-item config:name="ProtectForm" config:type="boolean">false</config:config-item><config:config-item config:name="PrintBlackFonts" config:type="boolean">false</config:config-item><config:config-item config:name="PrintProspectRTL" config:type="boolean">false</config:config-item><config:config-item config:name="BackgroundParaOverDrawings" config:type="boolean">false</config:config-item><config:config-item config:name="FloattableNomargins" config:type="boolean">false</config:config-item><config:config-item config:name="SmallCapsPercentage66" config:type="boolean">false</config:config-item><config:config-item config:name="PrintControls" config:type="boolean">true</config:config-item><config:config-item config:name="EmbedSystemFonts" config:type="boolean">false</config:config-item><config:config-item config:name="CharacterCompressionType" config:type="short">0</config:config-item><config:config-item config:name="PrintHiddenText" config:type="boolean">false</config:config-item><config:config-item config:name="UseFormerTextWrapping" config:type="boolean">false</config:config-item><config:config-item config:name="IsKernAsianPunctuation" config:type="boolean">false</config:config-item><config:config-item config:name="PrintProspect" config:type="boolean">false</config:config-item><config:config-item config:name="PrintEmptyPages" config:type="boolean">false</config:config-item><config:config-item config:name="UnbreakableNumberings" config:type="boolean">false</config:config-item><config:config-item config:name="UseFormerObjectPositioning" config:type="boolean">false</config:config-item><config:config-item config:name="ConsiderTextWrapOnObjPos" config:type="boolean">false</config:config-item><config:config-item config:name="TableRowKeep" config:type="boolean">false</config:config-item><config:config-item config:name="PrintReversed" config:type="boolean">false</config:config-item><config:config-item config:name="TabsRelativeToIndent" config:type="boolean">true</config:config-item><config:config-item config:name="PrintRightPages" config:type="boolean">true</config:config-item><config:config-item config:name="PrintPaperFromSetup" config:type="boolean">false</config:config-item><config:config-item config:name="AddFrameOffsets" config:type="boolean">false</config:config-item><config:config-item config:name="AddParaSpacingToTableCells" config:type="boolean">true</config:config-item><config:config-item config:name="UpdateFromTemplate" config:type="boolean">true</config:config-item><config:config-item config:name="AddExternalLeading" config:type="boolean">true</config:config-item><config:config-item config:name="PrintSingleJobs" config:type="boolean">false</config:config-item><config:config-item config:name="PrinterIndependentLayout" config:type="string">high-resolution</config:config-item><config:config-item config:name="RsidRoot" config:type="int">1473719</config:config-item><config:config-item config:name="LinkUpdateMode" config:type="short">1</config:config-item><config:config-item config:name="PrintAnnotationMode" config:type="short">0</config:config-item><config:config-item config:name="TabOverMargin" config:type="boolean">false</config:config-item><config:config-item config:name="UseOldPrinterMetrics" config:type="boolean">false</config:config-item><config:config-item config:name="RedlineProtectionKey" config:type="base64Binary"/><config:config-item config:name="PrinterSetup" config:type="base64Binary"/><config:config-item config:name="IgnoreFirstLineIndentInNumbering" config:type="boolean">false</config:config-item><config:config-item config:name="CollapseEmptyCellPara" config:type="boolean">true</config:config-item><config:config-item config:name="PrinterName" config:type="string"/><config:config-item config:name="EmbedFonts" config:type="boolean">false</config:config-item><config:config-item config:name="InvertBorderSpacing" config:type="boolean">false</config:config-item><config:config-item config:name="PrintPageBackground" config:type="boolean">true</config:config-item><config:config-item config:name="DoNotCaptureDrawObjsOnPage" config:type="boolean">false</config:config-item><config:config-item config:name="TabOverflow" config:type="boolean">true</config:config-item><config:config-item config:name="ApplyUserData" config:type="boolean">true</config:config-item><config:config-item config:name="TabAtLeftIndentForParagraphsInList" config:type="boolean">false</config:config-item><config:config-item config:name="UnxForceZeroExtLeading" config:type="boolean">false</config:config-item><config:config-item config:name="SaveVersionOnClose" config:type="boolean">false</config:config-item><config:config-item config:name="PrintFaxName" config:type="string"/><config:config-item config:name="StylesNoDefault" config:type="boolean">false</config:config-item><config:config-item config:name="AddParaTableSpacing" config:type="boolean">true</config:config-item><config:config-item config:name="PrintDrawings" config:type="boolean">true</config:config-item><config:config-item config:name="LoadReadonly" config:type="boolean">false</config:config-item><config:config-item config:name="PrintGraphics" config:type="boolean">true</config:config-item><config:config-item config:name="FieldAutoUpdate" config:type="boolean">true</config:config-item><config:config-item config:name="AllowPrintJobCancel" config:type="boolean">true</config:config-item><config:config-item config:name="UseFormerLineSpacing" config:type="boolean">false</config:config-item><config:config-item config:name="SaveGlobalDocumentLinks" config:type="boolean">false</config:config-item><config:config-item config:name="CurrentDatabaseDataSource" config:type="string"/><config:config-item config:name="IgnoreTabsAndBlanksForLineCalculation" config:type="boolean">false</config:config-item><config:config-item config:name="CurrentDatabaseCommandType" config:type="int">0</config:config-item><config:config-item config:name="DoNotResetParaAttrsForNumFont" config:type="boolean">false</config:config-item><config:config-item config:name="ClipAsCharacterAnchoredWriterFlyFrames" config:type="boolean">false</config:config-item><config:config-item config:name="PrintTables" config:type="boolean">true</config:config-item><config:config-item config:name="AddParaTableSpacingAtStart" config:type="boolean">true</config:config-item></config:config-item-set></office:settings></office:document-settings> \ No newline at end of file
diff --git a/data/odt/styles.xml b/data/odt/styles.xml
new file mode 100644
index 000000000..32b918406
--- /dev/null
+++ b/data/odt/styles.xml
@@ -0,0 +1,1096 @@
+<?xml version="1.0" encoding="utf-8"?>
+<office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0"
+xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0"
+xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0"
+xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0"
+xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0"
+xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0"
+xmlns:xlink="http://www.w3.org/1999/xlink"
+xmlns:dc="http://purl.org/dc/elements/1.1/"
+xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0"
+xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0"
+xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"
+xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0"
+xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0"
+xmlns:math="http://www.w3.org/1998/Math/MathML"
+xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0"
+xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0"
+xmlns:ooo="http://openoffice.org/2004/office"
+xmlns:ooow="http://openoffice.org/2004/writer"
+xmlns:oooc="http://openoffice.org/2004/calc"
+xmlns:dom="http://www.w3.org/2001/xml-events"
+xmlns:rpt="http://openoffice.org/2005/report"
+xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
+xmlns:xhtml="http://www.w3.org/1999/xhtml"
+xmlns:grddl="http://www.w3.org/2003/g/data-view#"
+xmlns:officeooo="http://openoffice.org/2009/office"
+xmlns:tableooo="http://openoffice.org/2009/table"
+xmlns:drawooo="http://openoffice.org/2010/draw"
+xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0"
+xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2">
+ <office:font-face-decls>
+ <style:font-face style:name="StarSymbol"
+ svg:font-family="StarSymbol" />
+ <style:font-face style:name="Tahoma1"
+ svg:font-family="Tahoma" />
+ <style:font-face style:name="Courier New"
+ svg:font-family="'Courier New'"
+ style:font-family-generic="modern" style:font-pitch="fixed" />
+ <style:font-face style:name="Times New Roman"
+ svg:font-family="'Times New Roman'"
+ style:font-family-generic="roman"
+ style:font-pitch="variable" />
+ <style:font-face style:name="Arial" svg:font-family="Arial"
+ style:font-family-generic="swiss"
+ style:font-pitch="variable" />
+ <style:font-face style:name="Lucida Sans Unicode"
+ svg:font-family="'Lucida Sans Unicode'"
+ style:font-family-generic="system"
+ style:font-pitch="variable" />
+ <style:font-face style:name="Tahoma" svg:font-family="Tahoma"
+ style:font-family-generic="system"
+ style:font-pitch="variable" />
+ </office:font-face-decls>
+ <office:styles>
+ <style:default-style style:family="graphic">
+ <style:graphic-properties fo:wrap-option="wrap"
+ draw:shadow-offset-x="0.1181in"
+ draw:shadow-offset-y="0.1181in"
+ draw:start-line-spacing-horizontal="0.1114in"
+ draw:start-line-spacing-vertical="0.1114in"
+ draw:end-line-spacing-horizontal="0.1114in"
+ draw:end-line-spacing-vertical="0.1114in"
+ style:flow-with-text="false" />
+ <style:paragraph-properties style:text-autospace="ideograph-alpha"
+ style:line-break="strict" style:writing-mode="lr-tb"
+ style:font-independent-line-spacing="false">
+ <style:tab-stops />
+ </style:paragraph-properties>
+ <style:text-properties style:use-window-font-color="true"
+ fo:font-size="12pt" fo:language="en" fo:country="US"
+ style:letter-kerning="true" style:font-size-asian="12pt"
+ style:language-asian="zxx" style:country-asian="none"
+ style:font-size-complex="12pt" style:language-complex="zxx"
+ style:country-complex="none" />
+ </style:default-style>
+ <style:default-style style:family="paragraph">
+ <style:paragraph-properties fo:hyphenation-ladder-count="no-limit"
+ style:text-autospace="ideograph-alpha"
+ style:punctuation-wrap="hanging" style:line-break="strict"
+ style:tab-stop-distance="0.4925in"
+ style:writing-mode="page" />
+ <style:text-properties style:use-window-font-color="true"
+ style:font-name="Times New Roman" fo:font-size="12pt"
+ fo:language="en" fo:country="US" style:letter-kerning="true"
+ style:font-name-asian="Lucida Sans Unicode"
+ style:font-size-asian="12pt" style:language-asian="zxx"
+ style:country-asian="none" style:font-name-complex="Tahoma"
+ style:font-size-complex="12pt" style:language-complex="zxx"
+ style:country-complex="none" fo:hyphenate="false"
+ fo:hyphenation-remain-char-count="2"
+ fo:hyphenation-push-char-count="2" />
+ </style:default-style>
+ <style:default-style style:family="table">
+ <style:table-properties table:border-model="collapsing" />
+ </style:default-style>
+ <style:default-style style:family="table-row">
+ <style:table-row-properties fo:keep-together="auto" />
+ </style:default-style>
+ <style:style style:name="Standard" style:family="paragraph"
+ style:class="text" />
+ <style:style style:name="Heading" style:family="paragraph"
+ style:parent-style-name="Standard"
+ style:next-style-name="Text_20_body" style:class="text">
+ <style:paragraph-properties fo:margin-top="0.1665in"
+ fo:margin-bottom="0.0835in" style:contextual-spacing="false"
+ fo:keep-with-next="always" />
+ <style:text-properties style:font-name="Arial"
+ fo:font-size="14pt"
+ style:font-name-asian="Lucida Sans Unicode"
+ style:font-size-asian="14pt" style:font-name-complex="Tahoma"
+ style:font-size-complex="14pt" />
+ </style:style>
+ <style:style style:name="Text_20_body"
+ style:display-name="Text body" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="text">
+ <style:paragraph-properties fo:margin-top="0.0598in"
+ fo:margin-bottom="0.0598in"
+ style:contextual-spacing="false" />
+ </style:style>
+ <style:style style:name="List" style:family="paragraph"
+ style:parent-style-name="Text_20_body" style:class="list">
+ <style:text-properties style:font-name-complex="Tahoma1" />
+ </style:style>
+ <style:style style:name="Caption" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:margin-top="0.0835in"
+ fo:margin-bottom="0.0835in" style:contextual-spacing="false"
+ text:number-lines="false" text:line-number="0" />
+ <style:text-properties fo:font-size="12pt"
+ fo:font-style="italic" style:font-size-asian="12pt"
+ style:font-style-asian="italic"
+ style:font-name-complex="Tahoma1"
+ style:font-size-complex="12pt"
+ style:font-style-complex="italic" />
+ </style:style>
+ <style:style style:name="TableCaption" style:family="paragraph"
+ style:parent-style-name="Caption" style:class="extra">
+ </style:style>
+ <style:style style:name="FigureCaption" style:family="paragraph"
+ style:parent-style-name="Caption" style:class="extra">
+ </style:style>
+ <style:style style:name="Figure" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties text:number-lines="false"
+ text:line-number="0" />
+ </style:style>
+ <style:style style:name="FigureWithCaption" style:family="paragraph"
+ style:parent-style-name="Figure" style:class="extra">
+ <style:paragraph-properties text:number-lines="false"
+ text:line-number="0" fo:keep-with-next="always" />
+ </style:style>
+ <style:style style:name="Index" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="index">
+ <style:paragraph-properties text:number-lines="false"
+ text:line-number="0" />
+ <style:text-properties style:font-name-complex="Tahoma1" />
+ </style:style>
+ <style:style style:name="Heading_20_1"
+ style:display-name="Heading 1" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="1" style:class="text">
+ <style:text-properties fo:font-size="115%"
+ fo:font-weight="bold" style:font-size-asian="115%"
+ style:font-weight-asian="bold" style:font-size-complex="115%"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Heading_20_2"
+ style:display-name="Heading 2" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="2" style:class="text">
+ <style:text-properties fo:font-size="14pt"
+ fo:font-style="italic" fo:font-weight="bold"
+ style:font-size-asian="14pt" style:font-style-asian="italic"
+ style:font-weight-asian="bold" style:font-size-complex="14pt"
+ style:font-style-complex="italic"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Heading_20_3"
+ style:display-name="Heading 3" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="3" style:class="text">
+ <style:text-properties fo:font-size="14pt"
+ fo:font-weight="bold" style:font-size-asian="14pt"
+ style:font-weight-asian="bold" style:font-size-complex="14pt"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Heading_20_4"
+ style:display-name="Heading 4" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="4" style:class="text">
+ <style:text-properties fo:font-size="85%"
+ fo:font-style="italic" fo:font-weight="bold"
+ style:font-size-asian="85%" style:font-style-asian="italic"
+ style:font-weight-asian="bold" style:font-size-complex="85%"
+ style:font-style-complex="italic"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Heading_20_5"
+ style:display-name="Heading 5" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="5" style:class="text">
+ <style:text-properties fo:font-size="85%"
+ fo:font-weight="bold" style:font-size-asian="85%"
+ style:font-weight-asian="bold" style:font-size-complex="85%"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Heading_20_6"
+ style:display-name="Heading 6" style:family="paragraph"
+ style:parent-style-name="Heading"
+ style:next-style-name="Text_20_body"
+ style:default-outline-level="6" style:class="text">
+ <style:text-properties fo:font-size="75%"
+ fo:font-weight="bold" style:font-size-asian="75%"
+ style:font-weight-asian="bold" style:font-size-complex="75%"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Quotations" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="html">
+ <style:paragraph-properties fo:margin-left="0.3937in"
+ fo:margin-right="0.3937in" fo:margin-top="0.1in"
+ fo:margin-bottom="0.1in" style:contextual-spacing="false"
+ fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="Preformatted_20_Text"
+ style:display-name="Preformatted Text" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="html">
+ <style:paragraph-properties fo:margin-top="0in"
+ fo:margin-bottom="0in" style:contextual-spacing="false" />
+ <style:text-properties style:font-name="Courier New"
+ fo:font-size="10pt" style:font-name-asian="Courier New"
+ style:font-size-asian="10pt"
+ style:font-name-complex="Courier New"
+ style:font-size-complex="10pt" />
+ </style:style>
+ <style:style style:name="Definition_20_Term"
+ style:display-name="Definition Term" style:family="paragraph"
+ style:parent-style-name="Standard"
+ style:next-style-name="Definition_20_Definition">
+ <style:paragraph-properties fo:margin-top="0.0598in"
+ fo:margin-bottom="0.0598in"
+ style:contextual-spacing="false" />
+ </style:style>
+ <style:style style:name="Definition_20_Definition"
+ style:display-name="Definition Definition"
+ style:family="paragraph" style:parent-style-name="Standard"
+ style:next-style-name="Text_20_body">
+ <style:paragraph-properties fo:margin-left="0.5in"
+ fo:margin-right="0in" fo:text-indent="0in"
+ style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="Table_20_Contents"
+ style:display-name="Table Contents" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:margin-left="0.0299in"
+ fo:margin-right="0.0299in" fo:text-indent="0in"
+ style:auto-text-indent="false" text:number-lines="false"
+ text:line-number="0" />
+ </style:style>
+ <style:style style:name="Table_20_Heading"
+ style:display-name="Table Heading" style:family="paragraph"
+ style:parent-style-name="Table_20_Contents"
+ style:class="extra">
+ <style:paragraph-properties fo:margin-left="0.0299in"
+ fo:margin-right="0.0299in" fo:text-align="start"
+ style:justify-single-word="false" fo:text-indent="0in"
+ style:auto-text-indent="false" style:shadow="none"
+ text:number-lines="false" text:line-number="0" />
+ <style:text-properties fo:font-weight="bold"
+ style:font-weight-asian="bold"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Footnote" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties fo:margin-left="0.1965in"
+ fo:margin-right="0in" fo:text-indent="-0.1965in"
+ style:auto-text-indent="false" text:number-lines="false"
+ text:line-number="0" />
+ <style:text-properties fo:font-size="10pt"
+ style:font-size-asian="10pt"
+ style:font-size-complex="10pt" />
+ </style:style>
+ <style:style style:name="Footer" style:family="paragraph"
+ style:parent-style-name="Standard" style:class="extra">
+ <style:paragraph-properties text:number-lines="false"
+ text:line-number="0">
+ <style:tab-stops>
+ <style:tab-stop style:position="3.25in"
+ style:type="center" />
+ <style:tab-stop style:position="6.5in"
+ style:type="right" />
+ </style:tab-stops>
+ </style:paragraph-properties>
+ </style:style>
+ <style:style style:name="Definition_20_Term_20_Tight"
+ style:display-name="Definition Term Tight"
+ style:family="paragraph" style:parent-style-name="Standard"
+ style:next-style-name="Definition_20_Definition_20_Tight">
+ <style:paragraph-properties fo:margin-top="0.0799in"
+ fo:margin-bottom="0.0799in"
+ style:contextual-spacing="false" />
+ </style:style>
+ <style:style style:name="Definition_20_Definition_20_Tight"
+ style:display-name="Definition Definition Tight"
+ style:family="paragraph" style:parent-style-name="Standard">
+ <style:paragraph-properties fo:margin-left="0.5in"
+ fo:margin-right="0in" fo:margin-top="0in"
+ fo:margin-bottom="0in" style:contextual-spacing="false"
+ fo:text-indent="0in" style:auto-text-indent="false" />
+ </style:style>
+ <style:style style:name="Date" style:family="paragraph"
+ style:parent-style-name="Standard"
+ style:next-style-name="Text_20_body">
+ <style:text-properties fo:font-style="italic" />
+ </style:style>
+ <style:style style:name="Author" style:family="paragraph"
+ style:parent-style-name="Standard" style:next-style-name="Date"
+ style:master-page-name="">
+ <style:paragraph-properties style:page-number="auto" />
+ <style:text-properties fo:font-style="italic" />
+ </style:style>
+ <style:style style:name="Horizontal_20_Line"
+ style:display-name="Horizontal Line" style:family="paragraph"
+ style:parent-style-name="Standard"
+ style:next-style-name="Text_20_body" style:class="html">
+ <style:paragraph-properties fo:margin-top="0in"
+ fo:margin-bottom="0.1965in" style:contextual-spacing="false"
+ style:border-line-width-bottom="0.0008in 0.0138in 0.0008in"
+ fo:padding="0in" fo:border-left="none" fo:border-right="none"
+ fo:border-top="none" fo:border-bottom="1.11pt double #808080"
+ text:number-lines="false" text:line-number="0"
+ style:join-border="false" />
+ <style:text-properties fo:font-size="6pt"
+ style:font-size-asian="6pt" style:font-size-complex="6pt" />
+ </style:style>
+ <style:style style:name="First_20_paragraph"
+ style:display-name="First paragraph" style:family="paragraph"
+ style:parent-style-name="Standard"
+ style:next-style-name="Text_20_body" style:class="text" />
+ <style:style style:name="Numbering_20_Symbols"
+ style:display-name="Numbering Symbols" style:family="text" />
+ <style:style style:name="Bullet_20_Symbols"
+ style:display-name="Bullet Symbols" style:family="text">
+ <style:text-properties style:font-name="StarSymbol"
+ fo:font-size="9pt" style:font-name-asian="StarSymbol"
+ style:font-size-asian="9pt"
+ style:font-name-complex="StarSymbol"
+ style:font-size-complex="9pt" />
+ </style:style>
+ <style:style style:name="Emphasis" style:family="text">
+ <style:text-properties fo:font-style="italic"
+ style:font-style-asian="italic"
+ style:font-style-complex="italic" />
+ </style:style>
+ <style:style style:name="Strong_20_Emphasis"
+ style:display-name="Strong Emphasis" style:family="text">
+ <style:text-properties fo:font-weight="bold"
+ style:font-weight-asian="bold"
+ style:font-weight-complex="bold" />
+ </style:style>
+ <style:style style:name="Strikeout" style:family="text">
+ <style:text-properties style:text-line-through-style="solid" />
+ </style:style>
+ <style:style style:name="Superscript" style:family="text">
+ <style:text-properties style:text-position="super 58%" />
+ </style:style>
+ <style:style style:name="Subscript" style:family="text">
+ <style:text-properties style:text-position="sub 58%" />
+ </style:style>
+ <style:style style:name="Citation" style:family="text">
+ <style:text-properties fo:font-style="italic"
+ style:font-style-asian="italic"
+ style:font-style-complex="italic" />
+ </style:style>
+ <style:style style:name="Teletype" style:family="text">
+ <style:text-properties style:font-name="Courier New"
+ style:font-name-asian="Courier New"
+ style:font-name-complex="Courier New" />
+ </style:style>
+ <style:style style:name="Internet_20_link"
+ style:display-name="Internet link" style:family="text">
+ <style:text-properties fo:color="#000080"
+ style:text-underline-style="solid"
+ style:text-underline-width="auto"
+ style:text-underline-color="font-color" />
+ </style:style>
+ <style:style style:name="Footnote_20_Symbol"
+ style:display-name="Footnote Symbol" style:family="text" />
+ <style:style style:name="Footnote_20_anchor"
+ style:display-name="Footnote anchor" style:family="text">
+ <style:text-properties style:text-position="super 58%" />
+ </style:style>
+ <style:style style:name="Definition" style:family="text" />
+ <text:outline-style style:name="Outline">
+ <text:outline-level-style text:level="1" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="2" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="3" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="4" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="5" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="6" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="7" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="8" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="9" style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ <text:outline-level-style text:level="10"
+ style:num-format="">
+ <style:list-level-properties text:min-label-distance="0.15in" />
+ </text:outline-level-style>
+ </text:outline-style>
+ <text:list-style style:name="Numbering_20_1"
+ style:display-name="Numbering 1">
+ <text:list-level-style-number text:level="1"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="0.1972in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="0.3937in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="0.5909in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="5"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="0.7874in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="6"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="0.9846in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="7"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="1.1815in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="8"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="1.3787in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="9"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="1.5752in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="10"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:space-before="1.7724in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="Numbering_20_2"
+ style:display-name="Numbering 2">
+ <text:list-level-style-number text:level="1"
+ text:style-name="Numbering_20_Symbols" style:num-format="1">
+ <style:list-level-properties text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="2">
+ <style:list-level-properties text:space-before="0.1965in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="3">
+ <style:list-level-properties text:space-before="0.3929in"
+ text:min-label-width="0.3937in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="4">
+ <style:list-level-properties text:space-before="0.7866in"
+ text:min-label-width="0.4925in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="5"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="5">
+ <style:list-level-properties text:space-before="1.2791in"
+ text:min-label-width="0.5902in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="6"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="6">
+ <style:list-level-properties text:space-before="1.8693in"
+ text:min-label-width="0.7091in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="7"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="7">
+ <style:list-level-properties text:space-before="2.5783in"
+ text:min-label-width="0.9055in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="8"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="8">
+ <style:list-level-properties text:space-before="3.4839in"
+ text:min-label-width="1.0236in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="9"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="9">
+ <style:list-level-properties text:space-before="4.5075in"
+ text:min-label-width="1.1028in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="10"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="10">
+ <style:list-level-properties text:space-before="5.6102in"
+ text:min-label-width="1.2209in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="Numbering_20_3"
+ style:display-name="Numbering 3">
+ <text:list-level-style-number text:level="1"
+ text:style-name="Numbering_20_Symbols" style:num-format="1">
+ <style:list-level-properties text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="2">
+ <style:list-level-properties text:space-before="1.1815in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="3">
+ <style:list-level-properties text:space-before="2.3626in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="4">
+ <style:list-level-properties text:space-before="3.5441in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="5"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="5">
+ <style:list-level-properties text:space-before="4.7252in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="6"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="6">
+ <style:list-level-properties text:space-before="5.9063in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="7"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="7">
+ <style:list-level-properties text:space-before="7.0878in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="8"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="8">
+ <style:list-level-properties text:space-before="8.2689in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="9"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="9">
+ <style:list-level-properties text:space-before="9.45in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="10"
+ text:style-name="Numbering_20_Symbols" style:num-format="1"
+ text:start-value="10">
+ <style:list-level-properties text:space-before="10.6315in"
+ text:min-label-width="1.1811in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="Numbering_20_4"
+ style:display-name="Numbering 4">
+ <text:list-level-style-number text:level="1"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I">
+ <style:list-level-properties text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="2">
+ <style:list-level-properties text:space-before="0.1972in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="3">
+ <style:list-level-properties text:space-before="0.3937in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="4"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="4">
+ <style:list-level-properties text:space-before="0.5909in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="5"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="5">
+ <style:list-level-properties text:space-before="0.7874in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="6"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="6">
+ <style:list-level-properties text:space-before="0.9846in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="7"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="7">
+ <style:list-level-properties text:space-before="1.1815in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="8"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="8">
+ <style:list-level-properties text:space-before="1.3787in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="9"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="9">
+ <style:list-level-properties text:space-before="1.5752in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="10"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="I" text:start-value="10">
+ <style:list-level-properties text:space-before="1.7724in"
+ text:min-label-width="0.1965in" />
+ </text:list-level-style-number>
+ </text:list-style>
+ <text:list-style style:name="Numbering_20_5"
+ style:display-name="Numbering 5">
+ <text:list-level-style-number text:level="1"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1">
+ <style:list-level-properties text:min-label-width="0.1575in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="2"
+ text:style-name="Numbering_20_Symbols" style:num-suffix="."
+ style:num-format="1" text:start-value="2"
+ text:display-levels="2">
+ <style:list-level-properties text:space-before="0.1772in"
+ text:min-label-width="0.2563in" />
+ </text:list-level-style-number>
+ <text:list-level-style-number text:level="3"
+ text:style-name="Numbering_20_Symbols" style:num-suffix=")"
+ style:num-format="a" text:start-value="3">
+ <style:list-level-properties text:space-before="0.4331in"
+ text:min-label-width="0.1772in" />
+ </text:list-level-style-number>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.6319in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.7874in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.9429in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.0988in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2543in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.4098in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.5654in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="List_20_1"
+ style:display-name="List 1">
+ <text:list-level-style-bullet text:level="1"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.1579in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.3146in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.4724in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.6299in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.7878in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="0.9445in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.1024in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.2598in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="•">
+ <style:list-level-properties text:space-before="1.4177in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="List_20_2"
+ style:display-name="List 2">
+ <text:list-level-style-bullet text:level="1"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.1181in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.2362in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.3539in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.472in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.5902in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.7091in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.8272in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="0.9453in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="–">
+ <style:list-level-properties text:space-before="1.063in"
+ text:min-label-width="0.1181in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="List_20_3"
+ style:display-name="List 3">
+ <text:list-level-style-bullet text:level="1"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="☑">
+ <style:list-level-properties text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="□">
+ <style:list-level-properties text:space-before="0.1555in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="☑">
+ <style:list-level-properties text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="□">
+ <style:list-level-properties text:space-before="0.1555in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="☑">
+ <style:list-level-properties text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="□">
+ <style:list-level-properties text:space-before="0.1555in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="☑">
+ <style:list-level-properties text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="□">
+ <style:list-level-properties text:space-before="0.1555in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="☑">
+ <style:list-level-properties text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="□">
+ <style:list-level-properties text:space-before="0.1555in"
+ text:min-label-width="0.1555in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="List_20_4"
+ style:display-name="List 4">
+ <text:list-level-style-bullet text:level="1"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="➢">
+ <style:list-level-properties text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.1579in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.3146in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.4724in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.6299in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.7878in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="0.9445in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="1.1024in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="1.2598in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="">
+ <style:list-level-properties text:space-before="1.4177in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:list-style style:name="List_20_5"
+ style:display-name="List 5">
+ <text:list-level-style-bullet text:level="1"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="2"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.1579in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="3"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.3146in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="4"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.4724in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="5"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.6299in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="6"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.7878in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="7"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="0.9445in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="8"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="1.1024in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="9"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="1.2598in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ <text:list-level-style-bullet text:level="10"
+ text:style-name="Numbering_20_Symbols" text:bullet-char="✗">
+ <style:list-level-properties text:space-before="1.4177in"
+ text:min-label-width="0.1575in" />
+ <style:text-properties style:font-name="StarSymbol" />
+ </text:list-level-style-bullet>
+ </text:list-style>
+ <text:notes-configuration text:note-class="footnote"
+ text:citation-style-name="Footnote_20_Symbol"
+ text:citation-body-style-name="Footnote_20_anchor"
+ style:num-format="1" text:start-value="0"
+ text:footnotes-position="page"
+ text:start-numbering-at="document" />
+ <text:notes-configuration text:note-class="endnote"
+ style:num-format="i" text:start-value="0" />
+ <text:linenumbering-configuration text:number-lines="false"
+ text:offset="0.1965in" style:num-format="1"
+ text:number-position="left" text:increment="5" />
+ </office:styles>
+ <office:automatic-styles>
+ <style:style style:name="MP1" style:family="paragraph"
+ style:parent-style-name="Footer">
+ <style:paragraph-properties fo:text-align="center"
+ style:justify-single-word="false" />
+ </style:style>
+ <style:page-layout style:name="Mpm1">
+ <style:page-layout-properties fo:page-width="8.5in"
+ fo:page-height="11in" style:num-format="1"
+ style:print-orientation="portrait" fo:margin-top="1in"
+ fo:margin-bottom="1in" fo:margin-left="1in"
+ fo:margin-right="1in" style:writing-mode="lr-tb"
+ style:footnote-max-height="0in">
+ <style:footnote-sep style:width="0.0071in"
+ style:distance-before-sep="0.0398in"
+ style:distance-after-sep="0.0398in" style:line-style="none"
+ style:adjustment="left" style:rel-width="25%"
+ style:color="#000000" />
+ </style:page-layout-properties>
+ <style:header-style />
+ <style:footer-style>
+ <style:header-footer-properties fo:min-height="0.4in"
+ fo:margin-left="0in" fo:margin-right="0in"
+ fo:margin-top="0.2in" style:dynamic-spacing="false" />
+ </style:footer-style>
+ </style:page-layout>
+ </office:automatic-styles>
+ <office:master-styles>
+ <style:master-page style:name="Standard"
+ style:page-layout-name="Mpm1">
+ <style:footer>
+ <text:p text:style-name="MP1">
+ <text:page-number text:select-page="current">
+ 1</text:page-number>
+ </text:p>
+ </style:footer>
+ </style:master-page>
+ </office:master-styles>
+</office:document-styles>
diff --git a/data/reference.docx b/data/reference.docx
deleted file mode 100644
index 0c717b3b6..000000000
--- a/data/reference.docx
+++ /dev/null
Binary files differ
diff --git a/data/reference.odt b/data/reference.odt
deleted file mode 100644
index c01345612..000000000
--- a/data/reference.odt
+++ /dev/null
Binary files differ
diff --git a/data/templates b/data/templates
-Subproject ec057f0ad3d191d18a2842e6a2fd41c471c6d97
+Subproject d171db3e6d28134e0f98ba10c60ac8c13380a48
diff --git a/deb/control.in b/deb/control.in
new file mode 100644
index 000000000..0aabf67a2
--- /dev/null
+++ b/deb/control.in
@@ -0,0 +1,20 @@
+Package: pandoc
+Version: VERSION
+Section: text
+Priority: optional
+Architecture: ARCHITECTURE
+Installed-Size: INSTALLED_SIZE
+Depends: libc6 (>= 2.11), libgmp10, zlib1g (>= 1:1.1.4)
+Maintainer: John MacFarlane <jgm@berkeley.edu>
+Description: general markup converter
+ Pandoc is a Haskell library for converting from one markup
+ format to another, and a command-line tool that uses
+ this library. It can read markdown and (subsets of) HTML,
+ reStructuredText, LaTeX, DocBook, MediaWiki markup, Twiki markup,
+ Haddock markup, OPML, Emacs Org-Mode, txt2tags and Textile, and
+ it can write markdown, reStructuredText, HTML, LaTeX, ConTeXt,
+ Docbook, OPML, OpenDocument, ODT, Word docx, RTF, MediaWiki,
+ DokuWiki, Textile, groff man pages, plain text, Emacs Org-Mode,
+ AsciiDoc, Haddock markup, EPUB (v2 and v3), FictionBook2,
+ InDesign ICML, and several kinds of HTML/javascript
+ slide shows (S5, Slidy, Slideous, DZSlides, reveal.js).
diff --git a/make_deb.sh b/make_deb.sh
new file mode 100755
index 000000000..a5aaf1549
--- /dev/null
+++ b/make_deb.sh
@@ -0,0 +1,63 @@
+#!/bin/bash -e
+
+MACHINE=$(uname -m)
+case "$MACHINE" in
+ x86_64) ARCHITECTURE=amd64;;
+ i686) ARCHITECTURE=i386;;
+ i386) ARCHITECTURE=i386;;
+esac
+
+SANDBOX=`pwd`/.cabal-sandbox
+VERSION=$(grep -e '^Version' pandoc.cabal | awk '{print $2}')
+DEBPKGVER=1
+DEBVER=$VERSION-$DEBPKGVER
+BASE=pandoc-$DEBVER-$ARCHITECTURE
+DIST=`pwd`/$BASE
+DEST=$DIST/usr
+ME=$(whoami)
+COPYRIGHT=$DEST/share/doc/pandoc/copyright
+
+# echo Removing old files...
+rm -rf $DIST
+
+cabal sandbox init
+echo Updating database
+cabal update
+
+export PATH=`pwd`/.cabal-sandbox/bin:$PATH
+which hsb2hs || cabal install hsb2hs
+echo Building pandoc...
+cabal clean
+cabal install --force --reinstall --flags="embed_data_files make-pandoc-man-pages" . pandoc-citeproc
+
+# get pandoc-citeproc man page:
+PANDOC_CITEPROC_PATH=`cabal unpack -d make_binary_package.tmp.$$ pandoc-citeproc | awk '{print $3;}'`
+strip $SANDBOX/bin/pandoc
+strip $SANDBOX/bin/pandoc-citeproc
+mkdir -p $DEST/bin
+mkdir -p $DEST/share/man/man1
+mkdir -p $DEST/share/doc/pandoc
+
+mkdir -p $DEST/share/doc/pandoc-citeproc
+find $DIST -type d | xargs chmod 755
+cp $SANDBOX/bin/pandoc $DEST/bin/
+cp $SANDBOX/bin/pandoc-citeproc $DEST/bin/
+cp $SANDBOX/share/man/man1/pandoc.1 $DEST/share/man/man1/pandoc.1
+gzip -9 $DEST/share/man/man1/pandoc.1
+cp $PANDOC_CITEPROC_PATH/man/man1/pandoc-citeproc.1 $DEST/share/man/man1/
+gzip -9 $DEST/share/man/man1/pandoc-citeproc.1
+cp COPYRIGHT $COPYRIGHT
+echo "" >> $COPYRIGHT
+echo "pandoc-citeproc" >> $COPYRIGHT
+cat $PANDOC_CITEPROC_PATH/LICENSE >> $COPYRIGHT
+rm -rf make_binary_package.tmp.$$
+
+INSTALLED_SIZE=$(du -B 1024 -s $DEST | awk '{print $1}')
+mkdir $DIST/DEBIAN
+perl -pe "s/VERSION/$DEBVER/" deb/control.in | \
+ perl -pe "s/ARCHITECTURE/$ARCHITECTURE/" | \
+ perl -pe "s/INSTALLED_SIZE/$INSTALLED_SIZE/" \
+ > $DIST/DEBIAN/control
+
+fakeroot dpkg-deb --build $DIST
+rm -rf $DIST
diff --git a/make_osx_package.sh b/make_osx_package.sh
index 6030f7032..e86ed18f2 100755
--- a/make_osx_package.sh
+++ b/make_osx_package.sh
@@ -5,7 +5,6 @@ SANDBOX=`pwd`/.cabal-sandbox
VERSION=$(grep -e '^Version' pandoc.cabal | awk '{print $2}')
RESOURCES=$DIST/Resources
ROOT=$DIST/pandoc
-MANDIR=`pwd`/man
DEST=$ROOT/usr/local
OSX=osx
SCRIPTS=$OSX/osx-resources
@@ -28,19 +27,17 @@ cabal clean
cabal install cpphs hsb2hs
cabal install --ghc-options="-optl-mmacosx-version-min=10.6" --reinstall --flags="embed_data_files make-pandoc-man-pages" --ghc-options "-pgmP$CPPHS -optP--cpp" . pandoc-citeproc
-make man
# get pandoc-citeproc man page:
PANDOC_CITEPROC_PATH=`cabal unpack -d $DIST pandoc-citeproc | awk '{print $3;}'`
-cp $PANDOC_CITEPROC_PATH/man/man1/pandoc-citeproc.1 $MANDIR/man1/
mkdir -p $DEST/bin
mkdir -p $DEST/share/man/man1
mkdir -p $DEST/share/man/man5
for f in pandoc pandoc-citeproc; do
cp $SANDBOX/bin/$f $DEST/bin/;
- cp $MANDIR/man1/$f.1 $DEST/share/man/man1/
done
-cp $MANDIR/man5/pandoc_markdown.5 $DEST/share/man/man5/
+cp $PANDOC_CITEPROC_PATH/man/man1/pandoc-citeproc.1 $DEST/share/man/man1/
+cp $SANDBOX/share/man/man1/pandoc.1 $DEST/share/man/man1/pandoc.1
chown -R $ME:staff $DIST
diff --git a/man/capitalizeHeaders.hs b/man/capitalizeHeaders.hs
new file mode 100644
index 000000000..863381c1f
--- /dev/null
+++ b/man/capitalizeHeaders.hs
@@ -0,0 +1,20 @@
+import Text.Pandoc.JSON
+import Text.Pandoc.Walk
+import Data.Char (toUpper)
+
+main :: IO ()
+main = toJSONFilter capitalizeHeaders
+
+capitalizeHeaders :: Block -> Block
+capitalizeHeaders (Header 1 attr xs) = Header 1 attr $ walk capitalize xs
+capitalizeHeaders x = x
+
+capitalize :: Inline -> Inline
+capitalize (Str xs) = Str $ map toUpper xs
+capitalize x = x
+
+{-
+capitalizeHeaderLinks :: Inline -> Inline
+capitalizeHeaderLinks (Link xs t@('#':_,_)) = Link (walk capitalize xs) t
+capitalizeHeaderLinks x = x
+-}
diff --git a/man/make-pandoc-man-pages.hs b/man/make-pandoc-man-pages.hs
deleted file mode 100644
index 65178a15b..000000000
--- a/man/make-pandoc-man-pages.hs
+++ /dev/null
@@ -1,104 +0,0 @@
-{-# LANGUAGE CPP #-}
--- Create pandoc.1 man and pandoc_markdown.5 man pages from README
-import Text.Pandoc
-import qualified Text.Pandoc.UTF8 as UTF8
-import Data.Char (toUpper)
-import Control.Monad
-import System.FilePath
-import System.Environment (getArgs)
-import Text.Pandoc.Shared (normalize)
-import Data.Maybe ( catMaybes )
-import Prelude hiding (catch)
-import Control.Exception ( catch )
-import System.IO.Error ( isDoesNotExistError )
-#if MIN_VERSION_directory(1,2,0)
-import Data.Time.Clock (UTCTime(..))
-#else
-import System.Time (ClockTime(..))
-#endif
-import System.Directory
-
-main :: IO ()
-main = do
- ds1 <- modifiedDependencies ("man" </> "man1" </> "pandoc.1")
- ["README", "man" </> "man1" </> "pandoc.1.template"]
- ds2 <- modifiedDependencies ("man" </> "man5" </> "pandoc_markdown.5")
- ["README", "man" </> "man5" </> "pandoc_markdown.5.template"]
-
- unless (null ds1 && null ds2) $ do
- rmContents <- UTF8.readFile "README"
- let (Pandoc meta blocks) = normalize $ readMarkdown def rmContents
- let manBlocks = removeSect [Str "Wrappers"]
- $ removeSect [Str "Pandoc's",Space,Str "markdown"] blocks
- let syntaxBlocks = extractSect [Str "Pandoc's",Space,Str "markdown"] blocks
- args <- getArgs
- let verbose = "--verbose" `elem` args
- unless (null ds1) $
- makeManPage verbose ("man" </> "man1" </> "pandoc.1") meta manBlocks
- unless (null ds2) $
- makeManPage verbose ("man" </> "man5" </> "pandoc_markdown.5") meta syntaxBlocks
-
-makeManPage :: Bool -> FilePath -> Meta -> [Block] -> IO ()
-makeManPage verbose page meta blocks = do
- let templ = page <.> "template"
- manTemplate <- UTF8.readFile templ
- writeManPage page manTemplate (Pandoc meta blocks)
- when verbose $ putStrLn $ "Created " ++ page
-
-writeManPage :: FilePath -> String -> Pandoc -> IO ()
-writeManPage page templ doc = do
- let version = pandocVersion
- let opts = def{ writerStandalone = True
- , writerTemplate = templ
- , writerVariables = [("version",version)] }
- let manPage = writeMan opts $
- bottomUp (concatMap removeLinks) $
- bottomUp capitalizeHeaders doc
- UTF8.writeFile page manPage
-
-removeLinks :: Inline -> [Inline]
-removeLinks (Link l _) = l
-removeLinks x = [x]
-
-capitalizeHeaders :: Block -> Block
-capitalizeHeaders (Header 1 attr xs) = Header 1 attr $ bottomUp capitalize xs
-capitalizeHeaders x = x
-
-capitalize :: Inline -> Inline
-capitalize (Str xs) = Str $ map toUpper xs
-capitalize x = x
-
-removeSect :: [Inline] -> [Block] -> [Block]
-removeSect ils (Header 1 _ x:xs) | x == ils =
- dropWhile (not . isHeader1) xs
-removeSect ils (x:xs) = x : removeSect ils xs
-removeSect _ [] = []
-
-extractSect :: [Inline] -> [Block] -> [Block]
-extractSect ils (Header 1 _ z:xs) | z == ils =
- bottomUp promoteHeader $ takeWhile (not . isHeader1) xs
- where promoteHeader (Header n attr x) = Header (n-1) attr x
- promoteHeader x = x
-extractSect ils (x:xs) = extractSect ils xs
-extractSect _ [] = []
-
-isHeader1 :: Block -> Bool
-isHeader1 (Header 1 _ _ ) = True
-isHeader1 _ = False
-
-
--- | Returns a list of 'dependencies' that have been modified after 'file'.
-modifiedDependencies :: FilePath -> [FilePath] -> IO [FilePath]
-modifiedDependencies file dependencies = do
- fileModTime <- catch (getModificationTime file) $
- \e -> if isDoesNotExistError e
-#if MIN_VERSION_directory(1,2,0)
- then return (UTCTime (toEnum 0) 0) -- the minimum ClockTime
-#else
- then return (TOD 0 0) -- the minimum ClockTime
-#endif
- else ioError e
- depModTimes <- mapM getModificationTime dependencies
- let modified = zipWith (\dep time -> if time > fileModTime then Just dep else Nothing) dependencies depModTimes
- return $ catMaybes modified
-
diff --git a/man/man1/pandoc.1.template b/man/man1/pandoc.1.template
deleted file mode 100644
index 00e7675e7..000000000
--- a/man/man1/pandoc.1.template
+++ /dev/null
@@ -1,16 +0,0 @@
-$if(has-tables)$
-.\"t
-$endif$
-.TH PANDOC 1 "$date$" "$version$"
-.SH NAME
-pandoc - general markup converter
-$body$
-.SH PANDOC'S MARKDOWN
-For a complete description of pandoc's extensions to standard markdown,
-see \f[C]pandoc_markdown\f[] (5).
-.SH SEE ALSO
-.PP
-\f[C]pandoc_markdown\f[] (5).
-.PP
-The Pandoc source code and all documentation may be downloaded
-from <http://johnmacfarlane.net/pandoc/>.
diff --git a/man/man5/pandoc_markdown.5.template b/man/man5/pandoc_markdown.5.template
deleted file mode 100644
index 6006e90c4..000000000
--- a/man/man5/pandoc_markdown.5.template
+++ /dev/null
@@ -1,11 +0,0 @@
-$if(has-tables)$
-.\"t
-$endif$
-.TH PANDOC_MARKDOWN 5 "$date$" "$version$"
-.SH NAME
-pandoc_markdown - markdown syntax for pandoc(1)
-.SH DESCRIPTION
-$body$
-.SH SEE ALSO
-.PP
-\f[C]pandoc\f[] (1).
diff --git a/man/pandoc.1 b/man/pandoc.1
new file mode 100644
index 000000000..2ffd794f6
--- /dev/null
+++ b/man/pandoc.1
@@ -0,0 +1,4336 @@
+.\"t
+.TH PANDOC 1 "July 15, 2015" ""
+.SH NAME
+pandoc - general markup converter
+.SH SYNOPSIS
+.PP
+\f[C]pandoc\f[] [\f[I]options\f[]] [\f[I]input\-file\f[]]...
+.SH DESCRIPTION
+.PP
+Pandoc is a Haskell library for converting from one markup format to
+another, and a command\-line tool that uses this library.
+It can read Markdown, CommonMark, and (subsets of) Textile,
+reStructuredText, HTML, LaTeX, MediaWiki markup, TWiki markup, Haddock
+markup, OPML, Emacs Org\-mode, DocBook, txt2tags, EPUB and Word docx;
+and it can write plain text, Markdown, reStructuredText, XHTML, HTML 5,
+LaTeX (including beamer slide shows), ConTeXt, RTF, OPML, DocBook,
+OpenDocument, ODT, Word docx, GNU Texinfo, MediaWiki markup, DokuWiki
+markup, Haddock markup, EPUB (v2 or v3), FictionBook2, Textile, groff
+man pages, Emacs Org\-Mode, AsciiDoc, InDesign ICML, and Slidy,
+Slideous, DZSlides, reveal.js or S5 HTML slide shows.
+It can also produce PDF output on systems where LaTeX is installed.
+.PP
+Pandoc\[aq]s enhanced version of markdown includes syntax for footnotes,
+tables, flexible ordered lists, definition lists, fenced code blocks,
+superscript, subscript, strikeout, title blocks, automatic tables of
+contents, embedded LaTeX math, citations, and markdown inside HTML block
+elements.
+(These enhancements, described below under Pandoc\[aq]s markdown, can be
+disabled using the \f[C]markdown_strict\f[] input or output format.)
+.PP
+In contrast to most existing tools for converting markdown to HTML,
+which use regex substitutions, Pandoc has a modular design: it consists
+of a set of readers, which parse text in a given format and produce a
+native representation of the document, and a set of writers, which
+convert this native representation into a target format.
+Thus, adding an input or output format requires only adding a reader or
+writer.
+.SS Using \f[C]pandoc\f[]
+.PP
+If no \f[I]input\-file\f[] is specified, input is read from
+\f[I]stdin\f[].
+Otherwise, the \f[I]input\-files\f[] are concatenated (with a blank line
+between each) and used as input.
+Output goes to \f[I]stdout\f[] by default (though output to
+\f[I]stdout\f[] is disabled for the \f[C]odt\f[], \f[C]docx\f[],
+\f[C]epub\f[], and \f[C]epub3\f[] output formats).
+For output to a file, use the \f[C]\-o\f[] option:
+.IP
+.nf
+\f[C]
+pandoc\ \-o\ output.html\ input.txt
+\f[]
+.fi
+.PP
+By default, pandoc produces a document fragment, not a standalone
+document with a proper header and footer.
+To produce a standalone document, use the \f[C]\-s\f[] or
+\f[C]\-\-standalone\f[] flag:
+.IP
+.nf
+\f[C]
+pandoc\ \-s\ \-o\ output.html\ input.txt
+\f[]
+.fi
+.PP
+For more information on how standalone documents are produced, see
+Templates, below.
+.PP
+Instead of a file, an absolute URI may be given.
+In this case pandoc will fetch the content using HTTP:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\ \-t\ markdown\ http://www.fsf.org
+\f[]
+.fi
+.PP
+If multiple input files are given, \f[C]pandoc\f[] will concatenate them
+all (with blank lines between them) before parsing.
+This feature is disabled for binary input formats such as \f[C]EPUB\f[]
+and \f[C]docx\f[].
+.PP
+The format of the input and output can be specified explicitly using
+command\-line options.
+The input format can be specified using the \f[C]\-r/\-\-read\f[] or
+\f[C]\-f/\-\-from\f[] options, the output format using the
+\f[C]\-w/\-\-write\f[] or \f[C]\-t/\-\-to\f[] options.
+Thus, to convert \f[C]hello.txt\f[] from markdown to LaTeX, you could
+type:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ markdown\ \-t\ latex\ hello.txt
+\f[]
+.fi
+.PP
+To convert \f[C]hello.html\f[] from html to markdown:
+.IP
+.nf
+\f[C]
+pandoc\ \-f\ html\ \-t\ markdown\ hello.html
+\f[]
+.fi
+.PP
+Supported output formats are listed below under the \f[C]\-t/\-\-to\f[]
+option.
+Supported input formats are listed below under the \f[C]\-f/\-\-from\f[]
+option.
+Note that the \f[C]rst\f[], \f[C]textile\f[], \f[C]latex\f[], and
+\f[C]html\f[] readers are not complete; there are some constructs that
+they do not parse.
+.PP
+If the input or output format is not specified explicitly,
+\f[C]pandoc\f[] will attempt to guess it from the extensions of the
+input and output filenames.
+Thus, for example,
+.IP
+.nf
+\f[C]
+pandoc\ \-o\ hello.tex\ hello.txt
+\f[]
+.fi
+.PP
+will convert \f[C]hello.txt\f[] from markdown to LaTeX.
+If no output file is specified (so that output goes to \f[I]stdout\f[]),
+or if the output file\[aq]s extension is unknown, the output format will
+default to HTML.
+If no input file is specified (so that input comes from \f[I]stdin\f[]),
+or if the input files\[aq] extensions are unknown, the input format will
+be assumed to be markdown unless explicitly specified.
+.PP
+Pandoc uses the UTF\-8 character encoding for both input and output.
+If your local character encoding is not UTF\-8, you should pipe input
+and output through \f[C]iconv\f[]:
+.IP
+.nf
+\f[C]
+iconv\ \-t\ utf\-8\ input.txt\ |\ pandoc\ |\ iconv\ \-f\ utf\-8
+\f[]
+.fi
+.PP
+Note that in some output formats (such as HTML, LaTeX, ConTeXt, RTF,
+OPML, DocBook, and Texinfo), information about the character encoding is
+included in the document header, which will only be included if you use
+the \f[C]\-s/\-\-standalone\f[] option.
+.SS Creating a PDF
+.PP
+Earlier versions of pandoc came with a program, \f[C]markdown2pdf\f[],
+that used pandoc and pdflatex to produce a PDF.
+This is no longer needed, since \f[C]pandoc\f[] can now produce
+\f[C]pdf\f[] output itself.
+To produce a PDF, simply specify an output file with a \f[C]\&.pdf\f[]
+extension.
+Pandoc will create a latex file and use pdflatex (or another engine, see
+\f[C]\-\-latex\-engine\f[]) to convert it to PDF:
+.IP
+.nf
+\f[C]
+pandoc\ test.txt\ \-o\ test.pdf
+\f[]
+.fi
+.PP
+Production of a PDF requires that a LaTeX engine be installed (see
+\f[C]\-\-latex\-engine\f[], below), and assumes that the following LaTeX
+packages are available: \f[C]amssymb\f[], \f[C]amsmath\f[],
+\f[C]ifxetex\f[], \f[C]ifluatex\f[], \f[C]listings\f[] (if the
+\f[C]\-\-listings\f[] option is used), \f[C]fancyvrb\f[],
+\f[C]longtable\f[], \f[C]booktabs\f[], \f[C]url\f[], \f[C]graphicx\f[]
+and \f[C]grffile\f[] (if the document contains images),
+\f[C]hyperref\f[], \f[C]ulem\f[], \f[C]babel\f[] (if the \f[C]lang\f[]
+variable is set), \f[C]fontspec\f[] (if \f[C]xelatex\f[] or
+\f[C]lualatex\f[] is used as the LaTeX engine), \f[C]xltxtra\f[] and
+\f[C]xunicode\f[] (if \f[C]xelatex\f[] is used).
+.SS \f[C]hsmarkdown\f[]
+.PP
+A user who wants a drop\-in replacement for \f[C]Markdown.pl\f[] may
+create a symbolic link to the \f[C]pandoc\f[] executable called
+\f[C]hsmarkdown\f[].
+When invoked under the name \f[C]hsmarkdown\f[], \f[C]pandoc\f[] will
+behave as if invoked with
+\f[C]\-f\ markdown_strict\ \-\-email\-obfuscation=references\f[], and
+all command\-line options will be treated as regular arguments.
+However, this approach does not work under Cygwin, due to problems with
+its simulation of symbolic links.
+.SH OPTIONS
+.SS General options
+.TP
+.B \f[C]\-f\f[] \f[I]FORMAT\f[], \f[C]\-r\f[] \f[I]FORMAT\f[], \f[C]\-\-from=\f[]\f[I]FORMAT\f[], \f[C]\-\-read=\f[]\f[I]FORMAT\f[]
+Specify input format.
+\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
+(JSON version of native AST), \f[C]markdown\f[] (pandoc\[aq]s extended
+markdown), \f[C]markdown_strict\f[] (original unextended markdown),
+\f[C]markdown_phpextra\f[] (PHP Markdown Extra extended markdown),
+\f[C]markdown_github\f[] (github extended markdown), \f[C]commonmark\f[]
+(CommonMark markdown), \f[C]textile\f[] (Textile), \f[C]rst\f[]
+(reStructuredText), \f[C]html\f[] (HTML), \f[C]docbook\f[] (DocBook),
+\f[C]t2t\f[] (txt2tags), \f[C]docx\f[] (docx), \f[C]epub\f[] (EPUB),
+\f[C]opml\f[] (OPML), \f[C]org\f[] (Emacs Org\-mode), \f[C]mediawiki\f[]
+(MediaWiki markup), \f[C]twiki\f[] (TWiki markup), \f[C]haddock\f[]
+(Haddock markup), or \f[C]latex\f[] (LaTeX).
+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.
+.RS
+.RE
+.TP
+.B \f[C]\-t\f[] \f[I]FORMAT\f[], \f[C]\-w\f[] \f[I]FORMAT\f[], \f[C]\-\-to=\f[]\f[I]FORMAT\f[], \f[C]\-\-write=\f[]\f[I]FORMAT\f[]
+Specify output format.
+\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
+(JSON version of native AST), \f[C]plain\f[] (plain text),
+\f[C]markdown\f[] (pandoc\[aq]s extended markdown),
+\f[C]markdown_strict\f[] (original unextended markdown),
+\f[C]markdown_phpextra\f[] (PHP Markdown extra extended markdown),
+\f[C]markdown_github\f[] (github extended markdown), \f[C]commonmark\f[]
+(CommonMark markdown), \f[C]rst\f[] (reStructuredText), \f[C]html\f[]
+(XHTML 1), \f[C]html5\f[] (HTML 5), \f[C]latex\f[] (LaTeX),
+\f[C]beamer\f[] (LaTeX beamer slide show), \f[C]context\f[] (ConTeXt),
+\f[C]man\f[] (groff man), \f[C]mediawiki\f[] (MediaWiki markup),
+\f[C]dokuwiki\f[] (DokuWiki markup), \f[C]textile\f[] (Textile),
+\f[C]org\f[] (Emacs Org\-Mode), \f[C]texinfo\f[] (GNU Texinfo),
+\f[C]opml\f[] (OPML), \f[C]docbook\f[] (DocBook), \f[C]opendocument\f[]
+(OpenDocument), \f[C]odt\f[] (OpenOffice text document), \f[C]docx\f[]
+(Word docx), \f[C]haddock\f[] (Haddock markup), \f[C]rtf\f[] (rich text
+format), \f[C]epub\f[] (EPUB v2 book), \f[C]epub3\f[] (EPUB v3),
+\f[C]fb2\f[] (FictionBook2 e\-book), \f[C]asciidoc\f[] (AsciiDoc),
+\f[C]icml\f[] (InDesign ICML), \f[C]slidy\f[] (Slidy HTML and javascript
+slide show), \f[C]slideous\f[] (Slideous HTML and javascript slide
+show), \f[C]dzslides\f[] (DZSlides HTML5 + javascript slide show),
+\f[C]revealjs\f[] (reveal.js HTML5 + javascript slide show), \f[C]s5\f[]
+(S5 HTML and javascript slide show), or the path of a custom lua writer
+(see Custom writers, below).
+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]html\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[].
+.RS
+.RE
+.TP
+.B \f[C]\-o\f[] \f[I]FILE\f[], \f[C]\-\-output=\f[]\f[I]FILE\f[]
+Write output to \f[I]FILE\f[] instead of \f[I]stdout\f[].
+If \f[I]FILE\f[] is \f[C]\-\f[], output will go to \f[I]stdout\f[].
+(Exception: if the output format is \f[C]odt\f[], \f[C]docx\f[],
+\f[C]epub\f[], or \f[C]epub3\f[], output to stdout is disabled.)
+.RS
+.RE
+.TP
+.B \f[C]\-\-data\-dir=\f[]\f[I]DIRECTORY\f[]
+Specify the user data directory to search for pandoc data files.
+If this option is not specified, the default user data directory will be
+used.
+This is
+.RS
+.IP
+.nf
+\f[C]
+$HOME/.pandoc
+\f[]
+.fi
+.PP
+in unix,
+.IP
+.nf
+\f[C]
+C:\\Documents\ And\ Settings\\USERNAME\\Application\ Data\\pandoc
+\f[]
+.fi
+.PP
+in Windows XP, and
+.IP
+.nf
+\f[C]
+C:\\Users\\USERNAME\\AppData\\Roaming\\pandoc
+\f[]
+.fi
+.PP
+in Windows 7.
+(You can find the default user data directory on your system by looking
+at the output of \f[C]pandoc\ \-\-version\f[].) A
+\f[C]reference.odt\f[], \f[C]reference.docx\f[], \f[C]default.csl\f[],
+\f[C]epub.css\f[], \f[C]templates\f[], \f[C]slidy\f[],
+\f[C]slideous\f[], or \f[C]s5\f[] directory placed in this directory
+will override pandoc\[aq]s normal defaults.
+.RE
+.TP
+.B \f[C]\-\-verbose\f[]
+Give verbose debugging output.
+Currently this only has an effect with PDF output.
+.RS
+.RE
+.TP
+.B \f[C]\-v\f[], \f[C]\-\-version\f[]
+Print version.
+.RS
+.RE
+.TP
+.B \f[C]\-h\f[], \f[C]\-\-help\f[]
+Show usage message.
+.RS
+.RE
+.SS Reader options
+.TP
+.B \f[C]\-R\f[], \f[C]\-\-parse\-raw\f[]
+Parse untranslatable HTML codes and LaTeX environments as raw HTML or
+LaTeX, instead of ignoring them.
+Affects only HTML and LaTeX input.
+Raw HTML can be printed in markdown, reStructuredText, HTML, Slidy,
+Slideous, DZSlides, reveal.js, and S5 output; raw LaTeX can be printed
+in markdown, reStructuredText, LaTeX, and ConTeXt output.
+The default is for the readers to omit untranslatable HTML codes and
+LaTeX environments.
+(The LaTeX reader does pass through untranslatable LaTeX
+\f[I]commands\f[], even if \f[C]\-R\f[] is not specified.)
+.RS
+.RE
+.TP
+.B \f[C]\-S\f[], \f[C]\-\-smart\f[]
+Produce typographically correct output, converting straight quotes to
+curly quotes, \f[C]\-\-\-\f[] to em\-dashes, \f[C]\-\-\f[] to
+en\-dashes, and \f[C]\&...\f[] to ellipses.
+Nonbreaking spaces are inserted after certain abbreviations, such as
+"Mr." (Note: This option is significant only when the input format is
+\f[C]markdown\f[], \f[C]markdown_strict\f[], \f[C]textile\f[] or
+\f[C]twiki\f[].
+It is selected automatically when the input format is \f[C]textile\f[]
+or the output format is \f[C]latex\f[] or \f[C]context\f[], unless
+\f[C]\-\-no\-tex\-ligatures\f[] is used.)
+.RS
+.RE
+.TP
+.B \f[C]\-\-old\-dashes\f[]
+Selects the pandoc <= 1.8.2.1 behavior for parsing smart dashes:
+\f[C]\-\f[] before a numeral is an en\-dash, and \f[C]\-\-\f[] is an
+em\-dash.
+This option is selected automatically for \f[C]textile\f[] input.
+.RS
+.RE
+.TP
+.B \f[C]\-\-base\-header\-level=\f[]\f[I]NUMBER\f[]
+Specify the base level for headers (defaults to 1).
+.RS
+.RE
+.TP
+.B \f[C]\-\-indented\-code\-classes=\f[]\f[I]CLASSES\f[]
+Specify classes to use for indented code blocks\-\-for example,
+\f[C]perl,numberLines\f[] or \f[C]haskell\f[].
+Multiple classes may be separated by spaces or commas.
+.RS
+.RE
+.TP
+.B \f[C]\-\-default\-image\-extension=\f[]\f[I]EXTENSION\f[]
+Specify a default extension to use when image paths/URLs have no
+extension.
+This allows you to use the same source for formats that require
+different kinds of images.
+Currently this option only affects the markdown and LaTeX readers.
+.RS
+.RE
+.TP
+.B \f[C]\-\-filter=\f[]\f[I]EXECUTABLE\f[]
+Specify an executable to be used as a filter transforming the Pandoc AST
+after the input is parsed and before the output is written.
+The executable should read JSON from stdin and write JSON to stdout.
+The JSON must be formatted like pandoc\[aq]s own JSON input and output.
+The name of the output format will be passed to the filter as the first
+argument.
+Hence,
+.RS
+.IP
+.nf
+\f[C]
+pandoc\ \-\-filter\ ./caps.py\ \-t\ latex
+\f[]
+.fi
+.PP
+is equivalent to
+.IP
+.nf
+\f[C]
+pandoc\ \-t\ json\ |\ ./caps.py\ latex\ |\ pandoc\ \-f\ json\ \-t\ latex
+\f[]
+.fi
+.PP
+The latter form may be useful for debugging filters.
+.PP
+Filters may be written in any language.
+\f[C]Text.Pandoc.JSON\f[] exports \f[C]toJSONFilter\f[] to facilitate
+writing filters in Haskell.
+Those who would prefer to write filters in python can use the module
+\f[C]pandocfilters\f[], installable from PyPI.
+See http://github.com/jgm/pandocfilters for the module and several
+examples.
+There are also pandoc filter libraries in PHP, perl, and
+javascript/node.js.
+.PP
+Note that the \f[I]EXECUTABLE\f[] will be sought in the user\[aq]s
+\f[C]PATH\f[], and not in the working directory, if no directory is
+provided.
+If you want to run a script in the working directory, preface the
+filename with \f[C]\&./\f[].
+.RE
+.TP
+.B \f[C]\-M\f[] \f[I]KEY\f[][\f[C]=\f[]\f[I]VAL\f[]], \f[C]\-\-metadata=\f[]\f[I]KEY\f[][\f[C]:\f[]\f[I]VAL\f[]]
+Set the metadata field \f[I]KEY\f[] to the value \f[I]VAL\f[].
+A value specified on the command line overrides a value specified in the
+document.
+Values will be parsed as YAML boolean or string values.
+If no value is specified, the value will be treated as Boolean true.
+Like \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] causes template
+variables to be set.
+But unlike \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] affects the
+metadata of the underlying document (which is accessible from filters
+and may be printed in some output formats).
+.RS
+.RE
+.TP
+.B \f[C]\-\-normalize\f[]
+Normalize the document after reading: merge adjacent \f[C]Str\f[] or
+\f[C]Emph\f[] elements, for example, and remove repeated
+\f[C]Space\f[]s.
+.RS
+.RE
+.TP
+.B \f[C]\-p\f[], \f[C]\-\-preserve\-tabs\f[]
+Preserve tabs instead of converting them to spaces (the default).
+Note that this will only affect tabs in literal code spans and code
+blocks; tabs in regular text will be treated as spaces.
+.RS
+.RE
+.TP
+.B \f[C]\-\-tab\-stop=\f[]\f[I]NUMBER\f[]
+Specify the number of spaces per tab (default is 4).
+.RS
+.RE
+.TP
+.B \f[C]\-\-track\-changes=accept\f[]|\f[C]reject\f[]|\f[C]all\f[]
+Specifies what to do with insertions and deletions produced by the MS
+Word "track\-changes" feature.
+\f[C]accept\f[] (the default), inserts all insertions, and ignores all
+deletions.
+\f[C]reject\f[] inserts all deletions and ignores insertions.
+\f[C]all\f[] puts in both insertions and deletions, wrapped in spans
+with \f[C]insertion\f[] and \f[C]deletion\f[] classes, respectively.
+The author and time of change is included.
+\f[C]all\f[] is useful for scripting: only accepting changes from a
+certain reviewer, say, or before a certain date.
+This option only affects the docx reader.
+.RS
+.RE
+.TP
+.B \f[C]\-\-extract\-media=\f[]\f[I]DIR\f[]
+Extract images and other media contained in a docx or epub container to
+the path \f[I]DIR\f[], creating it if necessary, and adjust the images
+references in the document so they point to the extracted files.
+This option only affects the docx and epub readers.
+.RS
+.RE
+.SS General writer options
+.TP
+.B \f[C]\-s\f[], \f[C]\-\-standalone\f[]
+Produce output with an appropriate header and footer (e.g.
+a standalone HTML, LaTeX, or RTF file, not a fragment).
+This option is set automatically for \f[C]pdf\f[], \f[C]epub\f[],
+\f[C]epub3\f[], \f[C]fb2\f[], \f[C]docx\f[], and \f[C]odt\f[] output.
+.RS
+.RE
+.TP
+.B \f[C]\-\-template=\f[]\f[I]FILE\f[]
+Use \f[I]FILE\f[] as a custom template for the generated document.
+Implies \f[C]\-\-standalone\f[].
+See Templates below for a description of template syntax.
+If no extension is specified, an extension corresponding to the writer
+will be added, so that \f[C]\-\-template=special\f[] looks for
+\f[C]special.html\f[] for HTML output.
+If the template is not found, pandoc will search for it in the
+\f[C]templates\f[] subdirectory of the user data directory (see
+\f[C]\-\-data\-dir\f[]).
+If this option is not used, a default template appropriate for the
+output format will be used (see
+\f[C]\-D/\-\-print\-default\-template\f[]).
+.RS
+.RE
+.TP
+.B \f[C]\-V\f[] \f[I]KEY\f[][\f[C]=\f[]\f[I]VAL\f[]], \f[C]\-\-variable=\f[]\f[I]KEY\f[][\f[C]:\f[]\f[I]VAL\f[]]
+Set the template variable \f[I]KEY\f[] to the value \f[I]VAL\f[] when
+rendering the document in standalone mode.
+This is generally only useful when the \f[C]\-\-template\f[] option is
+used to specify a custom template, since pandoc automatically sets the
+variables used in the default templates.
+If no \f[I]VAL\f[] is specified, the key will be given the value
+\f[C]true\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-D\f[] \f[I]FORMAT\f[], \f[C]\-\-print\-default\-template=\f[]\f[I]FORMAT\f[]
+Print the system default template for an output \f[I]FORMAT\f[].
+(See \f[C]\-t\f[] for a list of possible \f[I]FORMAT\f[]s.) Templates in
+the user data directory are ignored.
+.RS
+.RE
+.TP
+.B \f[C]\-\-print\-default\-data\-file=\f[]\f[I]FILE\f[]
+Print a system default data file.
+Files in the user data directory are ignored.
+.RS
+.RE
+.TP
+.B \f[C]\-\-no\-wrap\f[]
+Disable text wrapping in output.
+By default, text is wrapped appropriately for the output format.
+.RS
+.RE
+.TP
+.B \f[C]\-\-columns=\f[]\f[I]NUMBER\f[]
+Specify length of lines in characters (for text wrapping).
+.RS
+.RE
+.TP
+.B \f[C]\-\-toc\f[], \f[C]\-\-table\-of\-contents\f[]
+Include an automatically generated table of contents (or, in the case of
+\f[C]latex\f[], \f[C]context\f[], and \f[C]rst\f[], an instruction to
+create one) in the output document.
+This option has no effect on \f[C]man\f[], \f[C]docbook\f[],
+\f[C]slidy\f[], \f[C]slideous\f[], \f[C]s5\f[], \f[C]docx\f[], or
+\f[C]odt\f[] output.
+.RS
+.RE
+.TP
+.B \f[C]\-\-toc\-depth=\f[]\f[I]NUMBER\f[]
+Specify the number of section levels to include in the table of
+contents.
+The default is 3 (which means that level 1, 2, and 3 headers will be
+listed in the contents).
+.RS
+.RE
+.TP
+.B \f[C]\-\-no\-highlight\f[]
+Disables syntax highlighting for code blocks and inlines, even when a
+language attribute is given.
+.RS
+.RE
+.TP
+.B \f[C]\-\-highlight\-style=\f[]\f[I]STYLE\f[]
+Specifies the coloring style to be used in highlighted source code.
+Options are \f[C]pygments\f[] (the default), \f[C]kate\f[],
+\f[C]monochrome\f[], \f[C]espresso\f[], \f[C]zenburn\f[],
+\f[C]haddock\f[], and \f[C]tango\f[].
+For more information on syntax highlighting in pandoc, see Syntax
+highlighting, below.
+.RS
+.RE
+.TP
+.B \f[C]\-H\f[] \f[I]FILE\f[], \f[C]\-\-include\-in\-header=\f[]\f[I]FILE\f[]
+Include contents of \f[I]FILE\f[], verbatim, at the end of the header.
+This can be used, for example, to include special CSS or javascript in
+HTML documents.
+This option can be used repeatedly to include multiple files in the
+header.
+They will be included in the order specified.
+Implies \f[C]\-\-standalone\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-B\f[] \f[I]FILE\f[], \f[C]\-\-include\-before\-body=\f[]\f[I]FILE\f[]
+Include contents of \f[I]FILE\f[], verbatim, at the beginning of the
+document body (e.g.
+after the \f[C]<body>\f[] tag in HTML, or the \f[C]\\begin{document}\f[]
+command in LaTeX).
+This can be used to include navigation bars or banners in HTML
+documents.
+This option can be used repeatedly to include multiple files.
+They will be included in the order specified.
+Implies \f[C]\-\-standalone\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-A\f[] \f[I]FILE\f[], \f[C]\-\-include\-after\-body=\f[]\f[I]FILE\f[]
+Include contents of \f[I]FILE\f[], verbatim, at the end of the document
+body (before the \f[C]</body>\f[] tag in HTML, or the
+\f[C]\\end{document}\f[] command in LaTeX).
+This option can be be used repeatedly to include multiple files.
+They will be included in the order specified.
+Implies \f[C]\-\-standalone\f[].
+.RS
+.RE
+.SS Options affecting specific writers
+.TP
+.B \f[C]\-\-self\-contained\f[]
+Produce a standalone HTML file with no external dependencies, using
+\f[C]data:\f[] URIs to incorporate the contents of linked scripts,
+stylesheets, images, and videos.
+The resulting file should be "self\-contained," in the sense that it
+needs no external files and no net access to be displayed properly by a
+browser.
+This option works only with HTML output formats, including
+\f[C]html\f[], \f[C]html5\f[], \f[C]html+lhs\f[], \f[C]html5+lhs\f[],
+\f[C]s5\f[], \f[C]slidy\f[], \f[C]slideous\f[], \f[C]dzslides\f[], and
+\f[C]revealjs\f[].
+Scripts, images, and stylesheets at absolute URLs will be downloaded;
+those at relative URLs will be sought relative to the working directory
+(if the first source file is local) or relative to the base URL (if the
+first source file is remote).
+\f[C]\-\-self\-contained\f[] does not work with \f[C]\-\-mathjax\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-offline\f[]
+Deprecated synonym for \f[C]\-\-self\-contained\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-5\f[], \f[C]\-\-html5\f[]
+Produce HTML5 instead of HTML4.
+This option has no effect for writers other than \f[C]html\f[].
+(\f[I]Deprecated:\f[] Use the \f[C]html5\f[] output format instead.)
+.RS
+.RE
+.TP
+.B \f[C]\-\-html\-q\-tags\f[]
+Use \f[C]<q>\f[] tags for quotes in HTML.
+.RS
+.RE
+.TP
+.B \f[C]\-\-ascii\f[]
+Use only ascii characters in output.
+Currently supported only for HTML output (which uses numerical entities
+instead of UTF\-8 when this option is selected).
+.RS
+.RE
+.TP
+.B \f[C]\-\-reference\-links\f[]
+Use reference\-style links, rather than inline links, in writing
+markdown or reStructuredText.
+By default inline links are used.
+.RS
+.RE
+.TP
+.B \f[C]\-\-atx\-headers\f[]
+Use ATX style headers in markdown and asciidoc output.
+The default is to use setext\-style headers for levels 1\-2, and then
+ATX headers.
+.RS
+.RE
+.TP
+.B \f[C]\-\-chapters\f[]
+Treat top\-level headers as chapters in LaTeX, ConTeXt, and DocBook
+output.
+When the LaTeX template uses the report, book, or memoir class, this
+option is implied.
+If \f[C]beamer\f[] is the output format, top\-level headers will become
+\f[C]\\part{..}\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-N\f[], \f[C]\-\-number\-sections\f[]
+Number section headings in LaTeX, ConTeXt, HTML, or EPUB output.
+By default, sections are not numbered.
+Sections with class \f[C]unnumbered\f[] will never be numbered, even if
+\f[C]\-\-number\-sections\f[] is specified.
+.RS
+.RE
+.TP
+.B \f[C]\-\-number\-offset=\f[]\f[I]NUMBER\f[][\f[C],\f[]\f[I]NUMBER\f[]\f[C],\f[]\f[I]\&...\f[]]
+Offset for section headings in HTML output (ignored in other output
+formats).
+The first number is added to the section number for top\-level headers,
+the second for second\-level headers, and so on.
+So, for example, if you want the first top\-level header in your
+document to be numbered "6", specify \f[C]\-\-number\-offset=5\f[].
+If your document starts with a level\-2 header which you want to be
+numbered "1.5", specify \f[C]\-\-number\-offset=1,4\f[].
+Offsets are 0 by default.
+Implies \f[C]\-\-number\-sections\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-no\-tex\-ligatures\f[]
+Do not convert quotation marks, apostrophes, and dashes to the TeX
+ligatures when writing LaTeX or ConTeXt.
+Instead, just use literal unicode characters.
+This is needed for using advanced OpenType features with XeLaTeX and
+LuaLaTeX.
+Note: normally \f[C]\-\-smart\f[] is selected automatically for LaTeX
+and ConTeXt output, but it must be specified explicitly if
+\f[C]\-\-no\-tex\-ligatures\f[] is selected.
+If you use literal curly quotes, dashes, and ellipses in your source,
+then you may want to use \f[C]\-\-no\-tex\-ligatures\f[] without
+\f[C]\-\-smart\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-listings\f[]
+Use listings package for LaTeX code blocks
+.RS
+.RE
+.TP
+.B \f[C]\-i\f[], \f[C]\-\-incremental\f[]
+Make list items in slide shows display incrementally (one by one).
+The default is for lists to be displayed all at once.
+.RS
+.RE
+.TP
+.B \f[C]\-\-slide\-level=\f[]\f[I]NUMBER\f[]
+Specifies that headers with the specified level create slides (for
+\f[C]beamer\f[], \f[C]s5\f[], \f[C]slidy\f[], \f[C]slideous\f[],
+\f[C]dzslides\f[]).
+Headers above this level in the hierarchy are used to divide the slide
+show into sections; headers below this level create subheads within a
+slide.
+The default is to set the slide level based on the contents of the
+document; see Structuring the slide show, below.
+.RS
+.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.
+See Header identifiers, below.
+.RS
+.RE
+.TP
+.B \f[C]\-\-email\-obfuscation=none\f[]|\f[C]javascript\f[]|\f[C]references\f[]
+Specify a method for obfuscating \f[C]mailto:\f[] links in HTML
+documents.
+\f[C]none\f[] leaves \f[C]mailto:\f[] links as they are.
+\f[C]javascript\f[] obfuscates them using javascript.
+\f[C]references\f[] obfuscates them by printing their letters as decimal
+or hexadecimal character references.
+.RS
+.RE
+.TP
+.B \f[C]\-\-id\-prefix=\f[]\f[I]STRING\f[]
+Specify a prefix to be added to all automatically generated identifiers
+in HTML and DocBook output, and to footnote numbers in markdown output.
+This is useful for preventing duplicate identifiers when generating
+fragments to be included in other pages.
+.RS
+.RE
+.TP
+.B \f[C]\-T\f[] \f[I]STRING\f[], \f[C]\-\-title\-prefix=\f[]\f[I]STRING\f[]
+Specify \f[I]STRING\f[] as a prefix at the beginning of the title that
+appears in the HTML header (but not in the title as it appears at the
+beginning of the HTML body).
+Implies \f[C]\-\-standalone\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-c\f[] \f[I]URL\f[], \f[C]\-\-css=\f[]\f[I]URL\f[]
+Link to a CSS style sheet.
+This option can be be used repeatedly to include multiple files.
+They will be included in the order specified.
+.RS
+.RE
+.TP
+.B \f[C]\-\-reference\-odt=\f[]\f[I]FILE\f[]
+Use the specified file as a style reference in producing an ODT.
+For best results, the reference ODT should be a modified version of an
+ODT produced using pandoc.
+The contents of the reference ODT are ignored, but its stylesheets are
+used in the new ODT.
+If no reference ODT is specified on the command line, pandoc will look
+for a file \f[C]reference.odt\f[] in the user data directory (see
+\f[C]\-\-data\-dir\f[]).
+If this is not found either, sensible defaults will be used.
+.RS
+.RE
+.TP
+.B \f[C]\-\-reference\-docx=\f[]\f[I]FILE\f[]
+Use the specified file as a style reference in producing a docx file.
+For best results, the reference docx should be a modified version of a
+docx file produced using pandoc.
+The contents of the reference docx are ignored, but its stylesheets and
+document properties (including margins, page size, header, and footer)
+are used in the new docx.
+If no reference docx is specified on the command line, pandoc will look
+for a file \f[C]reference.docx\f[] in the user data directory (see
+\f[C]\-\-data\-dir\f[]).
+If this is not found either, sensible defaults will be used.
+The following styles are used by pandoc: [paragraph] Normal, Body Text,
+First Paragraph, Compact, Title, Subtitle, Author, Date, Abstract,
+Bibliography, Heading 1, Heading 2, Heading 3, Heading 4, Heading 5,
+Heading 6, Block Text, Footnote Text, Definition Term, Definition,
+Caption, Table Caption, Image Caption, Figure, Figure With Caption, TOC
+Heading; [character] Default Paragraph Font, Body Text Char, Verbatim
+Char, Footnote Reference, Hyperlink; [table] Normal Table.
+.RS
+.RE
+.TP
+.B \f[C]\-\-epub\-stylesheet=\f[]\f[I]FILE\f[]
+Use the specified CSS file to style the EPUB.
+If no stylesheet is specified, pandoc will look for a file
+\f[C]epub.css\f[] in the user data directory (see
+\f[C]\-\-data\-dir\f[]).
+If it is not found there, sensible defaults will be used.
+.RS
+.RE
+.TP
+.B \f[C]\-\-epub\-cover\-image=\f[]\f[I]FILE\f[]
+Use the specified image as the EPUB cover.
+It is recommended that the image be less than 1000px in width and
+height.
+Note that in a markdown source document you can also specify
+\f[C]cover\-image\f[] in a YAML metadata block (see EPUB Metadata,
+below).
+.RS
+.RE
+.TP
+.B \f[C]\-\-epub\-metadata=\f[]\f[I]FILE\f[]
+Look in the specified XML file for metadata for the EPUB.
+The file should contain a series of Dublin Core elements, as documented
+at http://dublincore.org/documents/dces/.
+For example:
+.RS
+.IP
+.nf
+\f[C]
+\ <dc:rights>Creative\ Commons</dc:rights>
+\ <dc:language>es\-AR</dc:language>
+\f[]
+.fi
+.PP
+By default, pandoc will include the following metadata elements:
+\f[C]<dc:title>\f[] (from the document title), \f[C]<dc:creator>\f[]
+(from the document authors), \f[C]<dc:date>\f[] (from the document date,
+which should be in ISO 8601 format), \f[C]<dc:language>\f[] (from the
+\f[C]lang\f[] variable, or, if is not set, the locale), and
+\f[C]<dc:identifier\ id="BookId">\f[] (a randomly generated UUID).
+Any of these may be overridden by elements in the metadata file.
+.PP
+Note: if the source document is markdown, a YAML metadata block in the
+document can be used instead.
+See below under EPUB Metadata.
+.RE
+.TP
+.B \f[C]\-\-epub\-embed\-font=\f[]\f[I]FILE\f[]
+Embed the specified font in the EPUB.
+This option can be repeated to embed multiple fonts.
+Wildcards can also be used: for example, \f[C]DejaVuSans\-*.ttf\f[].
+However, if you use wildcards on the command line, be sure to escape
+them or put the whole filename in single quotes, to prevent them from
+being interpreted by the shell.
+To use the embedded fonts, you will need to add declarations like the
+following to your CSS (see \f[C]\-\-epub\-stylesheet\f[]):
+.RS
+.IP
+.nf
+\f[C]
+\@font\-face\ {
+font\-family:\ DejaVuSans;
+font\-style:\ normal;
+font\-weight:\ normal;
+src:url("DejaVuSans\-Regular.ttf");
+}
+\@font\-face\ {
+font\-family:\ DejaVuSans;
+font\-style:\ normal;
+font\-weight:\ bold;
+src:url("DejaVuSans\-Bold.ttf");
+}
+\@font\-face\ {
+font\-family:\ DejaVuSans;
+font\-style:\ italic;
+font\-weight:\ normal;
+src:url("DejaVuSans\-Oblique.ttf");
+}
+\@font\-face\ {
+font\-family:\ DejaVuSans;
+font\-style:\ italic;
+font\-weight:\ bold;
+src:url("DejaVuSans\-BoldOblique.ttf");
+}
+body\ {\ font\-family:\ "DejaVuSans";\ }
+\f[]
+.fi
+.RE
+.TP
+.B \f[C]\-\-epub\-chapter\-level=\f[]\f[I]NUMBER\f[]
+Specify the header level at which to split the EPUB into separate
+"chapter" files.
+The default is to split into chapters at level 1 headers.
+This option only affects the internal composition of the EPUB, not the
+way chapters and sections are displayed to users.
+Some readers may be slow if the chapter files are too large, so for
+large documents with few level 1 headers, one might want to use a
+chapter level of 2 or 3.
+.RS
+.RE
+.TP
+.B \f[C]\-\-latex\-engine=pdflatex\f[]|\f[C]lualatex\f[]|\f[C]xelatex\f[]
+Use the specified LaTeX engine when producing PDF output.
+The default is \f[C]pdflatex\f[].
+If the engine is not in your PATH, the full path of the engine may be
+specified here.
+.RS
+.RE
+.TP
+.B \f[C]\-\-latex\-engine\-opt=\f[]\f[I]STRING\f[]
+Use the given string as a command\-line argument to the
+\f[C]latex\-engine\f[].
+If used multiple times, the arguments are provided with spaces between
+them.
+Note that no check for duplicate options is done.
+.RS
+.RE
+.SS Citation rendering
+.TP
+.B \f[C]\-\-bibliography=\f[]\f[I]FILE\f[]
+Set the \f[C]bibliography\f[] field in the document\[aq]s metadata to
+\f[I]FILE\f[], overriding any value set in the metadata, and process
+citations using \f[C]pandoc\-citeproc\f[].
+(This is equivalent to
+\f[C]\-\-metadata\ bibliography=FILE\ \-\-filter\ pandoc\-citeproc\f[].)
+If \f[C]\-\-natbib\f[] or \f[C]\-\-biblatex\f[] is also supplied,
+\f[C]pandoc\-citeproc\f[] is not used, making this equivalent to
+\f[C]\-\-metadata\ bibliography=FILE\f[].
+If you supply this argument multiple times, each \f[I]FILE\f[] will be
+added to bibliography.
+.RS
+.RE
+.TP
+.B \f[C]\-\-csl=\f[]\f[I]FILE\f[]
+Set the \f[C]csl\f[] field in the document\[aq]s metadata to
+\f[I]FILE\f[], overriding any value set in the metadata.
+(This is equivalent to \f[C]\-\-metadata\ csl=FILE\f[].) This option is
+only relevant with \f[C]pandoc\-citeproc\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-citation\-abbreviations=\f[]\f[I]FILE\f[]
+Set the \f[C]citation\-abbreviations\f[] field in the document\[aq]s
+metadata to \f[I]FILE\f[], overriding any value set in the metadata.
+(This is equivalent to
+\f[C]\-\-metadata\ citation\-abbreviations=FILE\f[].) This option is
+only relevant with \f[C]pandoc\-citeproc\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-natbib\f[]
+Use natbib for citations in LaTeX output.
+This option is not for use with the \f[C]pandoc\-citeproc\f[] filter or
+with PDF output.
+It is intended for use in producing a LaTeX file that can be processed
+with pdflatex and bibtex.
+.RS
+.RE
+.TP
+.B \f[C]\-\-biblatex\f[]
+Use biblatex for citations in LaTeX output.
+This option is not for use with the \f[C]pandoc\-citeproc\f[] filter or
+with PDF output.
+It is intended for use in producing a LaTeX file that can be processed
+with pdflatex and bibtex or biber.
+.RS
+.RE
+.SS Math rendering in HTML
+.TP
+.B \f[C]\-m\f[] [\f[I]URL\f[]], \f[C]\-\-latexmathml\f[][\f[C]=\f[]\f[I]URL\f[]]
+Use the LaTeXMathML script to display embedded TeX math in HTML output.
+To insert a link to a local copy of the \f[C]LaTeXMathML.js\f[] script,
+provide a \f[I]URL\f[].
+If no \f[I]URL\f[] is provided, the contents of the script will be
+inserted directly into the HTML header, preserving portability at the
+price of efficiency.
+If you plan to use math on several pages, it is much better to link to a
+copy of the script, so it can be cached.
+.RS
+.RE
+.TP
+.B \f[C]\-\-mathml\f[][\f[C]=\f[]\f[I]URL\f[]]
+Convert TeX math to MathML (in \f[C]docbook\f[] as well as \f[C]html\f[]
+and \f[C]html5\f[]).
+In standalone \f[C]html\f[] output, a small javascript (or a link to
+such a script if a \f[I]URL\f[] is supplied) will be inserted that
+allows the MathML to be viewed on some browsers.
+.RS
+.RE
+.TP
+.B \f[C]\-\-jsmath\f[][\f[C]=\f[]\f[I]URL\f[]]
+Use jsMath to display embedded TeX math in HTML output.
+The \f[I]URL\f[] should point to the jsMath load script (e.g.
+\f[C]jsMath/easy/load.js\f[]); if provided, it will be linked to in the
+header of standalone HTML documents.
+If a \f[I]URL\f[] is not provided, no link to the jsMath load script
+will be inserted; it is then up to the author to provide such a link in
+the HTML template.
+.RS
+.RE
+.TP
+.B \f[C]\-\-mathjax\f[][\f[C]=\f[]\f[I]URL\f[]]
+Use MathJax to display embedded TeX math in HTML output.
+The \f[I]URL\f[] should point to the \f[C]MathJax.js\f[] load script.
+If a \f[I]URL\f[] is not provided, a link to the MathJax CDN will be
+inserted.
+.RS
+.RE
+.TP
+.B \f[C]\-\-gladtex\f[]
+Enclose TeX math in \f[C]<eq>\f[] tags in HTML output.
+These can then be processed by gladTeX to produce links to images of the
+typeset formulas.
+.RS
+.RE
+.TP
+.B \f[C]\-\-mimetex\f[][\f[C]=\f[]\f[I]URL\f[]]
+Render TeX math using the mimeTeX CGI script.
+If \f[I]URL\f[] is not specified, it is assumed that the script is at
+\f[C]/cgi\-bin/mimetex.cgi\f[].
+.RS
+.RE
+.TP
+.B \f[C]\-\-webtex\f[][\f[C]=\f[]\f[I]URL\f[]]
+Render TeX formulas using an external script that converts TeX formulas
+to images.
+The formula will be concatenated with the URL provided.
+If \f[I]URL\f[] is not specified, the Google Chart API will be used.
+.RS
+.RE
+.TP
+.B \f[C]\-\-katex\f[][\f[C]=\f[]\f[I]URL\f[]]
+Use KaTeX to display embedded TeX math in HTML output.
+The \f[I]URL\f[] should point to the \f[C]katex.js\f[] load script.
+If a \f[I]URL\f[] is not provided, a link to the KaTeX CDN will be
+inserted.
+.RS
+.RE
+.TP
+.B \f[C]\-\-katex\-stylesheet=\f[]\f[I]URL\f[]
+The \f[I]URL\f[] should point to the \f[C]katex.css\f[] stylesheet.
+If this option is not specified, a link to the KaTeX CDN will be
+inserted.
+Note that this option does not imply \f[C]\-\-katex\f[].
+.RS
+.RE
+.SS Options for wrapper scripts
+.TP
+.B \f[C]\-\-dump\-args\f[]
+Print information about command\-line arguments to \f[I]stdout\f[], then
+exit.
+This option is intended primarily for use in wrapper scripts.
+The first line of output contains the name of the output file specified
+with the \f[C]\-o\f[] option, or \f[C]\-\f[] (for \f[I]stdout\f[]) if no
+output file was specified.
+The remaining lines contain the command\-line arguments, one per line,
+in the order they appear.
+These do not include regular Pandoc options and their arguments, but do
+include any options appearing after a \f[C]\-\-\f[] separator at the end
+of the line.
+.RS
+.RE
+.TP
+.B \f[C]\-\-ignore\-args\f[]
+Ignore command\-line arguments (for use in wrapper scripts).
+Regular Pandoc options are not ignored.
+Thus, for example,
+.RS
+.IP
+.nf
+\f[C]
+pandoc\ \-\-ignore\-args\ \-o\ foo.html\ \-s\ foo.txt\ \-\-\ \-e\ latin1
+\f[]
+.fi
+.PP
+is equivalent to
+.IP
+.nf
+\f[C]
+pandoc\ \-o\ foo.html\ \-s
+\f[]
+.fi
+.RE
+.SH TEMPLATES
+.PP
+When the \f[C]\-s/\-\-standalone\f[] option is used, pandoc uses a
+template to add header and footer material that is needed for a
+self\-standing document.
+To see the default template that is used, just type
+.IP
+.nf
+\f[C]
+pandoc\ \-D\ FORMAT
+\f[]
+.fi
+.PP
+where \f[C]FORMAT\f[] is the name of the output format.
+A custom template can be specified using the \f[C]\-\-template\f[]
+option.
+You can also override the system default templates for a given output
+format \f[C]FORMAT\f[] by putting a file
+\f[C]templates/default.FORMAT\f[] in the user data directory (see
+\f[C]\-\-data\-dir\f[], above).
+\f[I]Exceptions:\f[] For \f[C]odt\f[] output, customize the
+\f[C]default.opendocument\f[] template.
+For \f[C]pdf\f[] output, customize the \f[C]default.latex\f[] template.
+.PP
+Templates may contain \f[I]variables\f[].
+Variable names are sequences of alphanumerics, \f[C]\-\f[], and
+\f[C]_\f[], starting with a letter.
+A variable name surrounded by \f[C]$\f[] signs will be replaced by its
+value.
+For example, the string \f[C]$title$\f[] in
+.IP
+.nf
+\f[C]
+<title>$title$</title>
+\f[]
+.fi
+.PP
+will be replaced by the document title.
+.PP
+To write a literal \f[C]$\f[] in a template, use \f[C]$$\f[].
+.PP
+Some variables are set automatically by pandoc.
+These vary somewhat depending on the output format, but include metadata
+fields (such as \f[C]title\f[], \f[C]author\f[], and \f[C]date\f[]) as
+well as the following:
+.TP
+.B \f[C]header\-includes\f[]
+contents specified by \f[C]\-H/\-\-include\-in\-header\f[] (may have
+multiple values)
+.RS
+.RE
+.TP
+.B \f[C]toc\f[]
+non\-null value if \f[C]\-\-toc/\-\-table\-of\-contents\f[] was
+specified
+.RS
+.RE
+.TP
+.B \f[C]include\-before\f[]
+contents specified by \f[C]\-B/\-\-include\-before\-body\f[] (may have
+multiple values)
+.RS
+.RE
+.TP
+.B \f[C]include\-after\f[]
+contents specified by \f[C]\-A/\-\-include\-after\-body\f[] (may have
+multiple values)
+.RS
+.RE
+.TP
+.B \f[C]body\f[]
+body of document
+.RS
+.RE
+.TP
+.B \f[C]lang\f[]
+language code for HTML or LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]slidy\-url\f[]
+base URL for Slidy documents (defaults to
+\f[C]http://www.w3.org/Talks/Tools/Slidy2\f[])
+.RS
+.RE
+.TP
+.B \f[C]slideous\-url\f[]
+base URL for Slideous documents (defaults to \f[C]slideous\f[])
+.RS
+.RE
+.TP
+.B \f[C]s5\-url\f[]
+base URL for S5 documents (defaults to \f[C]s5/default\f[])
+.RS
+.RE
+.TP
+.B \f[C]revealjs\-url\f[]
+base URL for reveal.js documents (defaults to \f[C]reveal.js\f[])
+.RS
+.RE
+.TP
+.B \f[C]theme\f[]
+reveal.js or LaTeX beamer theme
+.RS
+.RE
+.TP
+.B \f[C]transition\f[]
+reveal.js transition
+.RS
+.RE
+.TP
+.B \f[C]fontsize\f[]
+font size (10pt, 11pt, 12pt) for LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]documentclass\f[]
+document class for LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]classoption\f[]
+option for LaTeX documentclass, e.g.
+\f[C]oneside\f[]; may be repeated for multiple options
+.RS
+.RE
+.TP
+.B \f[C]geometry\f[]
+options for LaTeX \f[C]geometry\f[] class, e.g.
+\f[C]margin=1in\f[]; may be repeated for multiple options
+.RS
+.RE
+.TP
+.B \f[C]linestretch\f[]
+adjusts line spacing (requires the \f[C]setspace\f[] package)
+.RS
+.RE
+.TP
+.B \f[C]fontfamily\f[]
+font package to use for LaTeX documents (with pdflatex): TeXLive has
+\f[C]bookman\f[] (Bookman), \f[C]utopia\f[] or \f[C]fourier\f[]
+(Utopia), \f[C]fouriernc\f[] (New Century Schoolbook), \f[C]times\f[] or
+\f[C]txfonts\f[] (Times), \f[C]mathpazo\f[] or \f[C]pxfonts\f[] or
+\f[C]mathpple\f[] (Palatino), \f[C]libertine\f[] (Linux Libertine),
+\f[C]arev\f[] (Arev Sans), and the default \f[C]lmodern\f[], among
+others.
+.RS
+.RE
+.TP
+.B \f[C]mainfont\f[], \f[C]sansfont\f[], \f[C]monofont\f[], \f[C]mathfont\f[], \f[C]CJKmainfont\f[]
+fonts for LaTeX documents (works only with xelatex and lualatex).
+Note that if \f[C]CJKmainfont\f[] is used, the \f[C]xeCJK\f[] package
+must be available.
+.RS
+.RE
+.TP
+.B \f[C]colortheme\f[]
+colortheme for LaTeX beamer documents
+.RS
+.RE
+.TP
+.B \f[C]fonttheme\f[]
+fonttheme for LaTeX beamer documents
+.RS
+.RE
+.TP
+.B \f[C]linkcolor\f[]
+color for internal links in LaTeX documents (\f[C]red\f[],
+\f[C]green\f[], \f[C]magenta\f[], \f[C]cyan\f[], \f[C]blue\f[],
+\f[C]black\f[])
+.RS
+.RE
+.TP
+.B \f[C]toccolor\f[]
+color for links in table of contents in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]urlcolor\f[]
+color for external links in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]citecolor\f[]
+color for citation links in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]links\-as\-notes\f[]
+causes links to be printed as footnotes in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]toc\f[]
+include table of contents in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]toc\-depth\f[]
+level of section to include in table of contents in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]toc\-title\f[]
+title of table of contents (works only with EPUB and docx)
+.RS
+.RE
+.TP
+.B \f[C]lof\f[]
+include list of figures in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]lot\f[]
+include list of tables in LaTeX documents
+.RS
+.RE
+.TP
+.B \f[C]bibliography\f[]
+bibliography to use for resolving references
+.RS
+.RE
+.TP
+.B \f[C]biblio\-style\f[]
+bibliography style in LaTeX, when used with \f[C]\-\-natbib\f[]
+.RS
+.RE
+.TP
+.B \f[C]section\f[]
+section number in man pages
+.RS
+.RE
+.TP
+.B \f[C]header\f[]
+header in man pages
+.RS
+.RE
+.TP
+.B \f[C]footer\f[]
+footer in man pages
+.RS
+.RE
+.PP
+Variables may be set at the command line using the
+\f[C]\-V/\-\-variable\f[] option.
+Variables set in this way override metadata fields with the same name.
+.PP
+Templates may contain conditionals.
+The syntax is as follows:
+.IP
+.nf
+\f[C]
+$if(variable)$
+X
+$else$
+Y
+$endif$
+\f[]
+.fi
+.PP
+This will include \f[C]X\f[] in the template if \f[C]variable\f[] has a
+non\-null value; otherwise it will include \f[C]Y\f[].
+\f[C]X\f[] and \f[C]Y\f[] are placeholders for any valid template text,
+and may include interpolated variables or other conditionals.
+The \f[C]$else$\f[] section may be omitted.
+.PP
+When variables can have multiple values (for example, \f[C]author\f[] in
+a multi\-author document), you can use the \f[C]$for$\f[] keyword:
+.IP
+.nf
+\f[C]
+$for(author)$
+<meta\ name="author"\ content="$author$"\ />
+$endfor$
+\f[]
+.fi
+.PP
+You can optionally specify a separator to be used between consecutive
+items:
+.IP
+.nf
+\f[C]
+$for(author)$$author$$sep$,\ $endfor$
+\f[]
+.fi
+.PP
+A dot can be used to select a field of a variable that takes an object
+as its value.
+So, for example:
+.IP
+.nf
+\f[C]
+$author.name$\ ($author.affiliation$)
+\f[]
+.fi
+.PP
+If you use custom templates, you may need to revise them as pandoc
+changes.
+We recommend tracking the changes in the default templates, and
+modifying your custom templates accordingly.
+An easy way to do this is to fork the pandoc\-templates repository
+(http://github.com/jgm/pandoc\-templates) and merge in changes after
+each pandoc release.
+.SH PANDOC\[aq]S MARKDOWN
+.PP
+Pandoc understands an extended and slightly revised version of John
+Gruber\[aq]s markdown syntax.
+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.
+.SS Philosophy
+.PP
+Markdown is designed to be easy to write, and, even more importantly,
+easy to read:
+.RS
+.PP
+A Markdown\-formatted document should be publishable as\-is, as plain
+text, without looking like it\[aq]s been marked up with tags or
+formatting instructions.
+\-\- John Gruber
+.RE
+.PP
+This principle has guided pandoc\[aq]s decisions in finding syntax for
+tables, footnotes, and other extensions.
+.PP
+There is, however, one respect in which pandoc\[aq]s aims are different
+from the original aims of markdown.
+Whereas markdown was originally designed with HTML generation in mind,
+pandoc is designed for multiple output formats.
+Thus, while pandoc allows the embedding of raw HTML, it discourages it,
+and provides other, non\-HTMLish ways of representing important document
+elements like definition lists, tables, mathematics, and footnotes.
+.SS Paragraphs
+.PP
+A paragraph is one or more lines of text followed by one or more blank
+lines.
+Newlines are treated as spaces, so you can reflow your paragraphs as you
+like.
+If you need a hard line break, put two or more spaces at the end of a
+line.
+.SS Extension: \f[C]escaped_line_breaks\f[]
+.PP
+A backslash followed by a newline is also a hard line break.
+Note: in multiline and grid table cells, this is the only way to create
+a hard line break, since trailing spaces in the cells are ignored.
+.SS Headers
+.PP
+There are two kinds of headers, Setext and atx.
+.SS Setext\-style headers
+.PP
+A setext\-style header is a line of text "underlined" with a row of
+\f[C]=\f[] signs (for a level one header) or \f[C]\-\f[] signs (for a
+level two header):
+.IP
+.nf
+\f[C]
+A\ level\-one\ header
+==================
+
+A\ level\-two\ header
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\f[]
+.fi
+.PP
+The header text can contain inline formatting, such as emphasis (see
+Inline formatting, below).
+.SS Atx\-style headers
+.PP
+An Atx\-style header consists of one to six \f[C]#\f[] signs and a line
+of text, optionally followed by any number of \f[C]#\f[] signs.
+The number of \f[C]#\f[] signs at the beginning of the line is the
+header level:
+.IP
+.nf
+\f[C]
+##\ A\ level\-two\ header
+
+###\ A\ level\-three\ header\ ###
+\f[]
+.fi
+.PP
+As with setext\-style headers, the header text can contain formatting:
+.IP
+.nf
+\f[C]
+#\ A\ level\-one\ header\ with\ a\ [link](/url)\ and\ *emphasis*
+\f[]
+.fi
+.SS Extension: \f[C]blank_before_header\f[]
+.PP
+Standard markdown syntax does not require a blank line before a header.
+Pandoc does require this (except, of course, at the beginning of the
+document).
+The reason for the requirement is that it is all too easy for a
+\f[C]#\f[] to end up at the beginning of a line by accident (perhaps
+through line wrapping).
+Consider, for example:
+.IP
+.nf
+\f[C]
+I\ like\ several\ of\ their\ flavors\ of\ ice\ cream:
+#22,\ for\ example,\ and\ #5.
+\f[]
+.fi
+.SS Header identifiers
+.SS Extension: \f[C]header_attributes\f[]
+.PP
+Headers can be assigned attributes using this syntax at the end of the
+line containing the header text:
+.IP
+.nf
+\f[C]
+{#identifier\ .class\ .class\ key=value\ key=value}
+\f[]
+.fi
+.PP
+Thus, for example, the following headers will all be assigned the
+identifier \f[C]foo\f[]:
+.IP
+.nf
+\f[C]
+#\ My\ header\ {#foo}
+
+##\ My\ header\ ##\ \ \ \ {#foo}
+
+My\ other\ header\ \ \ {#foo}
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\f[]
+.fi
+.PP
+(This syntax is compatible with PHP Markdown Extra.)
+.PP
+Note that although this syntax allows assignment of classes and
+key/value attributes, writers generally don\[aq]t use all of this
+information.
+Identifiers, classes, and key/value attributes are used in HTML and
+HTML\-based formats such as EPUB and slidy.
+Identifiers are used for labels and link anchors in the LaTeX, ConTeXt,
+Textile, and AsciiDoc writers.
+.PP
+Headers with the class \f[C]unnumbered\f[] will not be numbered, even if
+\f[C]\-\-number\-sections\f[] is specified.
+A single hyphen (\f[C]\-\f[]) in an attribute context is equivalent to
+\f[C]\&.unnumbered\f[], and preferable in non\-English documents.
+So,
+.IP
+.nf
+\f[C]
+#\ My\ header\ {\-}
+\f[]
+.fi
+.PP
+is just the same as
+.IP
+.nf
+\f[C]
+#\ 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{
+Header identifiers in HTML
+T}@T{
+\f[C]header\-identifiers\-in\-html\f[]
+T}
+T{
+\f[I]Dogs\f[]?\-\-in \f[I]my\f[] house?
+T}@T{
+\f[C]dogs\-\-in\-my\-house\f[]
+T}
+T{
+HTML, S5, or RTF?
+T}@T{
+\f[C]html\-s5\-or\-rtf\f[]
+T}
+T{
+3.
+Applications
+T}@T{
+\f[C]applications\f[]
+T}
+T{
+33
+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.
+So, instead of
+.IP
+.nf
+\f[C]
+[header\ identifiers](#header\-identifiers\-in\-html)
+\f[]
+.fi
+.PP
+you can simply write
+.IP
+.nf
+\f[C]
+[header\ identifiers]
+\f[]
+.fi
+.PP
+or
+.IP
+.nf
+\f[C]
+[header\ identifiers][]
+\f[]
+.fi
+.PP
+or
+.IP
+.nf
+\f[C]
+[the\ section\ on\ header\ identifiers][header\ identifiers]
+\f[]
+.fi
+.PP
+If there are multiple headers with identical text, the corresponding
+reference will link to the first one only, and you will need to use
+explicit links to link to the others, as described above.
+.PP
+Like regular reference links, these references are case\-insensitive.
+.PP
+Explicit link reference definitions always take priority over implicit
+header references.
+So, in the following example, the link will point to \f[C]bar\f[], not
+to \f[C]#foo\f[]:
+.IP
+.nf
+\f[C]
+#\ Foo
+
+[foo]:\ bar
+
+See\ [foo]
+\f[]
+.fi
+.SS Block quotations
+.PP
+Markdown uses email conventions for quoting blocks of text.
+A block quotation is one or more paragraphs or other block elements
+(such as lists or headers), with each line preceded by a \f[C]>\f[]
+character and a space.
+(The \f[C]>\f[] need not start at the left margin, but it should not be
+indented more than three spaces.)
+.IP
+.nf
+\f[C]
+>\ This\ is\ a\ block\ quote.\ This
+>\ paragraph\ has\ two\ lines.
+>
+>\ 1.\ This\ is\ a\ list\ inside\ a\ block\ quote.
+>\ 2.\ Second\ item.
+\f[]
+.fi
+.PP
+A "lazy" form, which requires the \f[C]>\f[] character only on the first
+line of each block, is also allowed:
+.IP
+.nf
+\f[C]
+>\ This\ is\ a\ block\ quote.\ This
+paragraph\ has\ two\ lines.
+
+>\ 1.\ This\ is\ a\ list\ inside\ a\ block\ quote.
+2.\ Second\ item.
+\f[]
+.fi
+.PP
+Among the block elements that can be contained in a block quote are
+other block quotes.
+That is, block quotes can be nested:
+.IP
+.nf
+\f[C]
+>\ This\ is\ a\ block\ quote.
+>
+>\ >\ A\ block\ quote\ within\ a\ block\ quote.
+\f[]
+.fi
+.SS Extension: \f[C]blank_before_blockquote\f[]
+.PP
+Standard markdown syntax does not require a blank line before a block
+quote.
+Pandoc does require this (except, of course, at the beginning of the
+document).
+The reason for the requirement is that it is all too easy for a
+\f[C]>\f[] to end up at the beginning of a line by accident (perhaps
+through line wrapping).
+So, unless the \f[C]markdown_strict\f[] format is used, the following
+does not produce a nested block quote in pandoc:
+.IP
+.nf
+\f[C]
+>\ This\ is\ a\ block\ quote.
+>>\ Nested.
+\f[]
+.fi
+.SS Verbatim (code) blocks
+.SS Indented code blocks
+.PP
+A block of text indented four spaces (or one tab) is treated as verbatim
+text: that is, special characters do not trigger special formatting, and
+all spaces and line breaks are preserved.
+For example,
+.IP
+.nf
+\f[C]
+\ \ \ \ if\ (a\ >\ 3)\ {
+\ \ \ \ \ \ moveShip(5\ *\ gravity,\ DOWN);
+\ \ \ \ }
+\f[]
+.fi
+.PP
+The initial (four space or one tab) indentation is not considered part
+of the verbatim text, and is removed in the output.
+.PP
+Note: blank lines in the verbatim text need not begin with four spaces.
+.SS Fenced code blocks
+.SS Extension: \f[C]fenced_code_blocks\f[]
+.PP
+In addition to standard indented code blocks, Pandoc supports
+\f[I]fenced\f[] code blocks.
+These begin with a row of three or more tildes (\f[C]~\f[]) and end with
+a row of tildes that must be at least as long as the starting row.
+Everything between these lines is treated as code.
+No indentation is necessary:
+.IP
+.nf
+\f[C]
+~~~~~~~
+if\ (a\ >\ 3)\ {
+\ \ moveShip(5\ *\ gravity,\ DOWN);
+}
+~~~~~~~
+\f[]
+.fi
+.PP
+Like regular code blocks, fenced code blocks must be separated from
+surrounding text by blank lines.
+.PP
+If the code itself contains a row of tildes or backticks, just use a
+longer row of tildes or backticks at the start and end:
+.IP
+.nf
+\f[C]
+~~~~~~~~~~~~~~~~
+~~~~~~~~~~
+code\ including\ tildes
+~~~~~~~~~~
+~~~~~~~~~~~~~~~~
+\f[]
+.fi
+.SS Extension: \f[C]backtick_code_blocks\f[]
+.PP
+Same as \f[C]fenced_code_blocks\f[], but uses backticks (\f[C]`\f[])
+instead of tildes (\f[C]~\f[]).
+.SS Extension: \f[C]fenced_code_attributes\f[]
+.PP
+Optionally, you may attach attributes to fenced or backtick code block
+using this syntax:
+.IP
+.nf
+\f[C]
+~~~~\ {#mycode\ .haskell\ .numberLines\ startFrom="100"}
+qsort\ []\ \ \ \ \ =\ []
+qsort\ (x:xs)\ =\ qsort\ (filter\ (<\ x)\ xs)\ ++\ [x]\ ++
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ qsort\ (filter\ (>=\ x)\ xs)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+\f[]
+.fi
+.PP
+Here \f[C]mycode\f[] is an identifier, \f[C]haskell\f[] and
+\f[C]numberLines\f[] are classes, and \f[C]startFrom\f[] is an attribute
+with value \f[C]100\f[].
+Some output formats can use this information to do syntax highlighting.
+Currently, the only output formats that uses this information are HTML
+and LaTeX.
+If highlighting is supported for your output format and language, then
+the code block above will appear highlighted, with numbered lines.
+(To see which languages are supported, do \f[C]pandoc\ \-\-version\f[].)
+Otherwise, the code block above will appear as follows:
+.IP
+.nf
+\f[C]
+<pre\ id="mycode"\ class="haskell\ numberLines"\ startFrom="100">
+\ \ <code>
+\ \ ...
+\ \ </code>
+</pre>
+\f[]
+.fi
+.PP
+A shortcut form can also be used for specifying the language of the code
+block:
+.IP
+.nf
+\f[C]
+```haskell
+qsort\ []\ =\ []
+```
+\f[]
+.fi
+.PP
+This is equivalent to:
+.IP
+.nf
+\f[C]
+```\ {.haskell}
+qsort\ []\ =\ []
+```
+\f[]
+.fi
+.PP
+If the \f[C]fenced_code_attributes\f[] extension is disabled, but input
+contains class attribute(s) for the codeblock, the first class attribute
+will be printed after the opening fence as a bare word.
+.PP
+To prevent all highlighting, use the \f[C]\-\-no\-highlight\f[] flag.
+To set the highlighting style, use \f[C]\-\-highlight\-style\f[].
+For more information on highlighting, see Syntax highlighting, below.
+.SS Line blocks
+.SS Extension: \f[C]line_blocks\f[]
+.PP
+A line block is a sequence of lines beginning with a vertical bar
+(\f[C]|\f[]) followed by a space.
+The division into lines will be preserved in the output, as will any
+leading spaces; otherwise, the lines will be formatted as markdown.
+This is useful for verse and addresses:
+.IP
+.nf
+\f[C]
+|\ The\ limerick\ packs\ laughs\ anatomical
+|\ In\ space\ that\ is\ quite\ economical.
+|\ \ \ \ But\ the\ good\ ones\ I\[aq]ve\ seen
+|\ \ \ \ So\ seldom\ are\ clean
+|\ And\ the\ clean\ ones\ so\ seldom\ are\ comical
+
+|\ 200\ Main\ St.
+|\ Berkeley,\ CA\ 94718
+\f[]
+.fi
+.PP
+The lines can be hard\-wrapped if needed, but the continuation line must
+begin with a space.
+.IP
+.nf
+\f[C]
+|\ The\ Right\ Honorable\ Most\ Venerable\ and\ Righteous\ Samuel\ L.
+\ \ Constable,\ Jr.
+|\ 200\ Main\ St.
+|\ Berkeley,\ CA\ 94718
+\f[]
+.fi
+.PP
+This syntax is borrowed from reStructuredText.
+.SS Lists
+.SS Bullet lists
+.PP
+A bullet list is a list of bulleted list items.
+A bulleted list item begins with a bullet (\f[C]*\f[], \f[C]+\f[], or
+\f[C]\-\f[]).
+Here is a simple example:
+.IP
+.nf
+\f[C]
+*\ one
+*\ two
+*\ three
+\f[]
+.fi
+.PP
+This will produce a "compact" list.
+If you want a "loose" list, in which each item is formatted as a
+paragraph, put spaces between the items:
+.IP
+.nf
+\f[C]
+*\ one
+
+*\ two
+
+*\ three
+\f[]
+.fi
+.PP
+The bullets need not be flush with the left margin; they may be indented
+one, two, or three spaces.
+The bullet must be followed by whitespace.
+.PP
+List items look best if subsequent lines are flush with the first line
+(after the bullet):
+.IP
+.nf
+\f[C]
+*\ here\ is\ my\ first
+\ \ list\ item.
+*\ and\ my\ second.
+\f[]
+.fi
+.PP
+But markdown also allows a "lazy" format:
+.IP
+.nf
+\f[C]
+*\ here\ is\ my\ first
+list\ item.
+*\ and\ my\ second.
+\f[]
+.fi
+.SS The four\-space rule
+.PP
+A list item may contain multiple paragraphs and other block\-level
+content.
+However, subsequent paragraphs must be preceded by a blank line and
+indented four spaces or a tab.
+The list will look better if the first paragraph is aligned with the
+rest:
+.IP
+.nf
+\f[C]
+\ \ *\ First\ paragraph.
+
+\ \ \ \ Continued.
+
+\ \ *\ Second\ paragraph.\ With\ a\ code\ block,\ which\ must\ be\ indented
+\ \ \ \ eight\ spaces:
+
+\ \ \ \ \ \ \ \ {\ code\ }
+\f[]
+.fi
+.PP
+List items may include other lists.
+In this case the preceding blank line is optional.
+The nested list must be indented four spaces or one tab:
+.IP
+.nf
+\f[C]
+*\ fruits
+\ \ \ \ +\ apples
+\ \ \ \ \ \ \ \ \-\ macintosh
+\ \ \ \ \ \ \ \ \-\ red\ delicious
+\ \ \ \ +\ pears
+\ \ \ \ +\ peaches
+*\ vegetables
+\ \ \ \ +\ broccoli
+\ \ \ \ +\ chard
+\f[]
+.fi
+.PP
+As noted above, markdown allows you to write list items "lazily,"
+instead of indenting continuation lines.
+However, if there are multiple paragraphs or other blocks in a list
+item, the first line of each must be indented.
+.IP
+.nf
+\f[C]
++\ A\ lazy,\ lazy,\ list
+item.
+
++\ Another\ one;\ this\ looks
+bad\ but\ is\ legal.
+
+\ \ \ \ Second\ paragraph\ of\ second
+list\ item.
+\f[]
+.fi
+.PP
+\f[B]Note:\f[] Although the four\-space rule for continuation paragraphs
+comes from the official markdown syntax guide, the reference
+implementation, \f[C]Markdown.pl\f[], does not follow it.
+So pandoc will give different results than \f[C]Markdown.pl\f[] when
+authors have indented continuation paragraphs fewer than four spaces.
+.PP
+The markdown syntax guide is not explicit whether the four\-space rule
+applies to \f[I]all\f[] block\-level content in a list item; it only
+mentions paragraphs and code blocks.
+But it implies that the rule applies to all block\-level content
+(including nested lists), and pandoc interprets it that way.
+.SS Ordered lists
+.PP
+Ordered lists work just like bulleted lists, except that the items begin
+with enumerators rather than bullets.
+.PP
+In standard markdown, enumerators are decimal numbers followed by a
+period and a space.
+The numbers themselves are ignored, so there is no difference between
+this list:
+.IP
+.nf
+\f[C]
+1.\ \ one
+2.\ \ two
+3.\ \ three
+\f[]
+.fi
+.PP
+and this one:
+.IP
+.nf
+\f[C]
+5.\ \ one
+7.\ \ two
+1.\ \ three
+\f[]
+.fi
+.SS Extension: \f[C]fancy_lists\f[]
+.PP
+Unlike standard markdown, Pandoc allows ordered list items to be marked
+with uppercase and lowercase letters and roman numerals, in addition to
+arabic numerals.
+List markers may be enclosed in parentheses or followed by a single
+right\-parentheses or period.
+They must be separated from the text that follows by at least one space,
+and, if the list marker is a capital letter with a period, by at least
+two spaces.
+.PP
+The \f[C]fancy_lists\f[] extension also allows \[aq]\f[C]#\f[]\[aq] to
+be used as an ordered list marker in place of a numeral:
+.IP
+.nf
+\f[C]
+#.\ one
+#.\ two
+\f[]
+.fi
+.SS Extension: \f[C]startnum\f[]
+.PP
+Pandoc also pays attention to the type of list marker used, and to the
+starting number, and both of these are preserved where possible in the
+output format.
+Thus, the following yields a list with numbers followed by a single
+parenthesis, starting with 9, and a sublist with lowercase roman
+numerals:
+.IP
+.nf
+\f[C]
+\ 9)\ \ Ninth
+10)\ \ Tenth
+11)\ \ Eleventh
+\ \ \ \ \ \ \ i.\ subone
+\ \ \ \ \ \ ii.\ subtwo
+\ \ \ \ \ iii.\ subthree
+\f[]
+.fi
+.PP
+Pandoc will start a new list each time a different type of list marker
+is used.
+So, the following will create three lists:
+.IP
+.nf
+\f[C]
+(2)\ Two
+(5)\ Three
+1.\ \ Four
+*\ \ \ Five
+\f[]
+.fi
+.PP
+If default list markers are desired, use \f[C]#.\f[]:
+.IP
+.nf
+\f[C]
+#.\ \ one
+#.\ \ two
+#.\ \ three
+\f[]
+.fi
+.SS Definition lists
+.SS Extension: \f[C]definition_lists\f[]
+.PP
+Pandoc supports definition lists, using the syntax of PHP Markdown Extra
+with some extensions.
+.IP
+.nf
+\f[C]
+Term\ 1
+
+:\ \ \ Definition\ 1
+
+Term\ 2\ with\ *inline\ markup*
+
+:\ \ \ Definition\ 2
+
+\ \ \ \ \ \ \ \ {\ some\ code,\ part\ of\ Definition\ 2\ }
+
+\ \ \ \ Third\ paragraph\ of\ definition\ 2.
+\f[]
+.fi
+.PP
+Each term must fit on one line, which may optionally be followed by a
+blank line, and must be followed by one or more definitions.
+A definition begins with a colon or tilde, which may be indented one or
+two spaces.
+.PP
+A term may have multiple definitions, and each definition may consist of
+one or more block elements (paragraph, code block, list, etc.), each
+indented four spaces or one tab stop.
+The body of the definition (including the first line, aside from the
+colon or tilde) should be indented four spaces.
+However, as with other markdown lists, you can "lazily" omit indentation
+except at the beginning of a paragraph or other block element:
+.IP
+.nf
+\f[C]
+Term\ 1
+
+:\ \ \ Definition
+with\ lazy\ continuation.
+
+\ \ \ \ Second\ paragraph\ of\ the\ definition.
+\f[]
+.fi
+.PP
+If you leave space before the definition (as in the example above), the
+text of the definition will be treated as a paragraph.
+In some output formats, this will mean greater spacing between
+term/definition pairs.
+For a more compact definition list, omit the space before the
+definition:
+.IP
+.nf
+\f[C]
+Term\ 1
+\ \ ~\ Definition\ 1
+
+Term\ 2
+\ \ ~\ Definition\ 2a
+\ \ ~\ Definition\ 2b
+\f[]
+.fi
+.PP
+Note that space between items in a definition list is required.
+(A variant that loosens this requirement, but disallows "lazy" hard
+wrapping, can be activated with \f[C]compact_definition_lists\f[]: see
+Non\-pandoc extensions, below.)
+.SS Numbered example lists
+.SS Extension: \f[C]example_lists\f[]
+.PP
+The special list marker \f[C]\@\f[] can be used for sequentially
+numbered examples.
+The first list item with a \f[C]\@\f[] marker will be numbered
+\[aq]1\[aq], the next \[aq]2\[aq], and so on, throughout the document.
+The numbered examples need not occur in a single list; each new list
+using \f[C]\@\f[] will take up where the last stopped.
+So, for example:
+.IP
+.nf
+\f[C]
+(\@)\ \ My\ first\ example\ will\ be\ numbered\ (1).
+(\@)\ \ My\ second\ example\ will\ be\ numbered\ (2).
+
+Explanation\ of\ examples.
+
+(\@)\ \ My\ third\ example\ will\ be\ numbered\ (3).
+\f[]
+.fi
+.PP
+Numbered examples can be labeled and referred to elsewhere in the
+document:
+.IP
+.nf
+\f[C]
+(\@good)\ \ This\ is\ a\ good\ example.
+
+As\ (\@good)\ illustrates,\ ...
+\f[]
+.fi
+.PP
+The label can be any string of alphanumeric characters, underscores, or
+hyphens.
+.SS Compact and loose lists
+.PP
+Pandoc behaves differently from \f[C]Markdown.pl\f[] on some "edge
+cases" involving lists.
+Consider this source:
+.IP
+.nf
+\f[C]
++\ \ \ First
++\ \ \ Second:
+\ \ \ \ \-\ \ \ Fee
+\ \ \ \ \-\ \ \ Fie
+\ \ \ \ \-\ \ \ Foe
+
++\ \ \ Third
+\f[]
+.fi
+.PP
+Pandoc transforms this into a "compact list" (with no \f[C]<p>\f[] tags
+around "First", "Second", or "Third"), while markdown puts \f[C]<p>\f[]
+tags around "Second" and "Third" (but not "First"), because of the blank
+space around "Third".
+Pandoc follows a simple rule: if the text is followed by a blank line,
+it is treated as a paragraph.
+Since "Second" is followed by a list, and not a blank line, it isn\[aq]t
+treated as a paragraph.
+The fact that the list is followed by a blank line is irrelevant.
+(Note: Pandoc works this way even when the \f[C]markdown_strict\f[]
+format is specified.
+This behavior is consistent with the official markdown syntax
+description, even though it is different from that of
+\f[C]Markdown.pl\f[].)
+.SS Ending a list
+.PP
+What if you want to put an indented code block after a list?
+.IP
+.nf
+\f[C]
+\-\ \ \ item\ one
+\-\ \ \ item\ two
+
+\ \ \ \ {\ my\ code\ block\ }
+\f[]
+.fi
+.PP
+Trouble! Here pandoc (like other markdown implementations) will treat
+\f[C]{\ my\ code\ block\ }\f[] as the second paragraph of item two, and
+not as a code block.
+.PP
+To "cut off" the list after item two, you can insert some non\-indented
+content, like an HTML comment, which won\[aq]t produce visible output in
+any format:
+.IP
+.nf
+\f[C]
+\-\ \ \ item\ one
+\-\ \ \ item\ two
+
+<!\-\-\ end\ of\ list\ \-\->
+
+\ \ \ \ {\ my\ code\ block\ }
+\f[]
+.fi
+.PP
+You can use the same trick if you want two consecutive lists instead of
+one big list:
+.IP
+.nf
+\f[C]
+1.\ \ one
+2.\ \ two
+3.\ \ three
+
+<!\-\-\ \-\->
+
+1.\ \ uno
+2.\ \ dos
+3.\ \ tres
+\f[]
+.fi
+.SS Horizontal rules
+.PP
+A line containing a row of three or more \f[C]*\f[], \f[C]\-\f[], or
+\f[C]_\f[] characters (optionally separated by spaces) produces a
+horizontal rule:
+.IP
+.nf
+\f[C]
+*\ \ *\ \ *\ \ *
+
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\f[]
+.fi
+.SS Tables
+.PP
+Four kinds of tables may be used.
+The first three kinds presuppose the use of a fixed\-width font, such as
+Courier.
+The fourth kind can be used with proportionally spaced fonts, as it does
+not require lining up columns.
+.SS Extension: \f[C]table_captions\f[]
+.PP
+A caption may optionally be provided with all 4 kinds of tables (as
+illustrated in the examples below).
+A caption is a paragraph beginning with the string \f[C]Table:\f[] (or
+just \f[C]:\f[]), which will be stripped off.
+It may appear either before or after the table.
+.SS Extension: \f[C]simple_tables\f[]
+.PP
+Simple tables look like this:
+.IP
+.nf
+\f[C]
+\ \ Right\ \ \ \ \ Left\ \ \ \ \ Center\ \ \ \ \ Default
+\-\-\-\-\-\-\-\ \ \ \ \ \-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\ \ \ \-\-\-\-\-\-\-
+\ \ \ \ \ 12\ \ \ \ \ 12\ \ \ \ \ \ \ \ 12\ \ \ \ \ \ \ \ \ \ \ \ 12
+\ \ \ \ 123\ \ \ \ \ 123\ \ \ \ \ \ \ 123\ \ \ \ \ \ \ \ \ \ 123
+\ \ \ \ \ \ 1\ \ \ \ \ 1\ \ \ \ \ \ \ \ \ \ 1\ \ \ \ \ \ \ \ \ \ \ \ \ 1
+
+Table:\ \ Demonstration\ of\ simple\ table\ syntax.
+\f[]
+.fi
+.PP
+The headers and table rows must each fit on one line.
+Column alignments are determined by the position of the header text
+relative to the dashed line below it:
+.IP \[bu] 2
+If the dashed line is flush with the header text on the right side but
+extends beyond it on the left, the column is right\-aligned.
+.IP \[bu] 2
+If the dashed line is flush with the header text on the left side but
+extends beyond it on the right, the column is left\-aligned.
+.IP \[bu] 2
+If the dashed line extends beyond the header text on both sides, the
+column is centered.
+.IP \[bu] 2
+If the dashed line is flush with the header text on both sides, the
+default alignment is used (in most cases, this will be left).
+.PP
+The table must end with a blank line, or a line of dashes followed by a
+blank line.
+.PP
+The column headers may be omitted, provided a dashed line is used to end
+the table.
+For example:
+.IP
+.nf
+\f[C]
+\-\-\-\-\-\-\-\ \ \ \ \ \-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\ \ \ \-\-\-\-\-\-\-
+\ \ \ \ \ 12\ \ \ \ \ 12\ \ \ \ \ \ \ \ 12\ \ \ \ \ \ \ \ \ \ \ \ \ 12
+\ \ \ \ 123\ \ \ \ \ 123\ \ \ \ \ \ \ 123\ \ \ \ \ \ \ \ \ \ \ 123
+\ \ \ \ \ \ 1\ \ \ \ \ 1\ \ \ \ \ \ \ \ \ \ 1\ \ \ \ \ \ \ \ \ \ \ \ \ \ 1
+\-\-\-\-\-\-\-\ \ \ \ \ \-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\ \ \ \-\-\-\-\-\-\-
+\f[]
+.fi
+.PP
+When headers are omitted, column alignments are determined on the basis
+of the first line of the table body.
+So, in the tables above, the columns would be right, left, center, and
+right aligned, respectively.
+.SS Extension: \f[C]multiline_tables\f[]
+.PP
+Multiline tables allow headers and table rows to span multiple lines of
+text (but cells that span multiple columns or rows of the table are not
+supported).
+Here is an example:
+.IP
+.nf
+\f[C]
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\ Centered\ \ \ Default\ \ \ \ \ \ \ \ \ \ \ Right\ Left
+\ \ Header\ \ \ \ Aligned\ \ \ \ \ \ \ \ \ Aligned\ Aligned
+\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\ \ \ First\ \ \ \ row\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 12.0\ Example\ of\ a\ row\ that
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ spans\ multiple\ lines.
+
+\ \ Second\ \ \ \ row\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 5.0\ Here\[aq]s\ another\ one.\ Note
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ blank\ line\ between
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rows.
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+
+Table:\ Here\[aq]s\ the\ caption.\ It,\ too,\ may\ span
+multiple\ lines.
+\f[]
+.fi
+.PP
+These work like simple tables, but with the following differences:
+.IP \[bu] 2
+They must begin with a row of dashes, before the header text (unless the
+headers are omitted).
+.IP \[bu] 2
+They must end with a row of dashes, then a blank line.
+.IP \[bu] 2
+The rows must be separated by blank lines.
+.PP
+In multiline tables, the table parser pays attention to the widths of
+the columns, and the writers try to reproduce these relative widths in
+the output.
+So, if you find that one of the columns is too narrow in the output, try
+widening it in the markdown source.
+.PP
+Headers may be omitted in multiline tables as well as simple tables:
+.IP
+.nf
+\f[C]
+\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+\ \ \ First\ \ \ \ row\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 12.0\ Example\ of\ a\ row\ that
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ spans\ multiple\ lines.
+
+\ \ Second\ \ \ \ row\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ 5.0\ Here\[aq]s\ another\ one.\ Note
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ the\ blank\ line\ between
+\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ rows.
+\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\ \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+
+:\ Here\[aq]s\ a\ multiline\ table\ without\ headers.
+\f[]
+.fi
+.PP
+It is possible for a multiline table to have just one row, but the row
+should be followed by a blank line (and then the row of dashes that ends
+the table), or the table may be interpreted as a simple table.
+.SS Extension: \f[C]grid_tables\f[]
+.PP
+Grid tables look like this:
+.IP
+.nf
+\f[C]
+:\ Sample\ grid\ table.
+
++\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+|\ Fruit\ \ \ \ \ \ \ \ \ |\ Price\ \ \ \ \ \ \ \ \ |\ Advantages\ \ \ \ \ \ \ \ \ |
++===============+===============+====================+
+|\ Bananas\ \ \ \ \ \ \ |\ $1.34\ \ \ \ \ \ \ \ \ |\ \-\ built\-in\ wrapper\ |
+|\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ |\ \-\ bright\ color\ \ \ \ \ |
++\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+|\ Oranges\ \ \ \ \ \ \ |\ $2.10\ \ \ \ \ \ \ \ \ |\ \-\ cures\ scurvy\ \ \ \ \ |
+|\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ |\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ |\ \-\ tasty\ \ \ \ \ \ \ \ \ \ \ \ |
++\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-+
+\f[]
+.fi
+.PP
+The row of \f[C]=\f[]s separates the header from the table body, and can
+be omitted for a headerless table.
+The cells of grid tables may contain arbitrary block elements (multiple
+paragraphs, code blocks, lists, etc.).
+Alignments are not supported, nor are cells that span multiple columns
+or rows.
+Grid tables can be created easily using Emacs table mode.
+.SS Extension: \f[C]pipe_tables\f[]
+.PP
+Pipe tables look like this:
+.IP
+.nf
+\f[C]
+|\ Right\ |\ Left\ |\ Default\ |\ Center\ |
+|\-\-\-\-\-\-:|:\-\-\-\-\-|\-\-\-\-\-\-\-\-\-|:\-\-\-\-\-\-:|
+|\ \ \ 12\ \ |\ \ 12\ \ |\ \ \ \ 12\ \ \ |\ \ \ \ 12\ \ |
+|\ \ 123\ \ |\ \ 123\ |\ \ \ 123\ \ \ |\ \ \ 123\ \ |
+|\ \ \ \ 1\ \ |\ \ \ \ 1\ |\ \ \ \ \ 1\ \ \ |\ \ \ \ \ 1\ \ |
+
+\ \ :\ Demonstration\ of\ pipe\ table\ syntax.
+\f[]
+.fi
+.PP
+The syntax is the same as in PHP markdown extra.
+The beginning and ending pipe characters are optional, but pipes are
+required between all columns.
+The colons indicate column alignment as shown.
+The header cannot be omitted.
+To simulate a headerless table, include a header with blank cells.
+.PP
+Since the pipes indicate column boundaries, columns need not be
+vertically aligned, as they are in the above example.
+So, this is a perfectly legal (though ugly) pipe table:
+.IP
+.nf
+\f[C]
+fruit|\ price
+\-\-\-\-\-|\-\-\-\-\-:
+apple|2.05
+pear|1.37
+orange|3.09
+\f[]
+.fi
+.PP
+The cells of pipe tables cannot contain block elements like paragraphs
+and lists, and cannot span multiple lines.
+Note also that in LaTeX/PDF output, the cells produced by pipe tables
+will not wrap, since there is no information available about relative
+widths.
+If you want content to wrap within cells, use multiline or grid tables.
+.PP
+Note: Pandoc also recognizes pipe tables of the following form, as can
+be produced by Emacs\[aq] orgtbl\-mode:
+.IP
+.nf
+\f[C]
+|\ One\ |\ Two\ \ \ |
+|\-\-\-\-\-+\-\-\-\-\-\-\-|
+|\ my\ \ |\ table\ |
+|\ is\ \ |\ nice\ \ |
+\f[]
+.fi
+.PP
+The difference is that \f[C]+\f[] is used instead of \f[C]|\f[].
+Other orgtbl features are not supported.
+In particular, to get non\-default column alignment, you\[aq]ll need to
+add colons as above.
+.SS Metadata blocks
+.SS Extension: \f[C]pandoc_title_block\f[]
+.PP
+If the file begins with a title block
+.IP
+.nf
+\f[C]
+%\ title
+%\ author(s)\ (separated\ by\ semicolons)
+%\ date
+\f[]
+.fi
+.PP
+it will be parsed as bibliographic information, not regular text.
+(It will be used, for example, in the title of standalone LaTeX or HTML
+output.) The block may contain just a title, a title and an author, or
+all three elements.
+If you want to include an author but no title, or a title and a date but
+no author, you need a blank line:
+.IP
+.nf
+\f[C]
+%
+%\ Author
+
+%\ My\ title
+%
+%\ June\ 15,\ 2006
+\f[]
+.fi
+.PP
+The title may occupy multiple lines, but continuation lines must begin
+with leading space, thus:
+.IP
+.nf
+\f[C]
+%\ My\ title
+\ \ on\ multiple\ lines
+\f[]
+.fi
+.PP
+If a document has multiple authors, the authors may be put on separate
+lines with leading space, or separated by semicolons, or both.
+So, all of the following are equivalent:
+.IP
+.nf
+\f[C]
+%\ Author\ One
+\ \ Author\ Two
+
+%\ Author\ One;\ Author\ Two
+
+%\ Author\ One;
+\ \ Author\ Two
+\f[]
+.fi
+.PP
+The date must fit on one line.
+.PP
+All three metadata fields may contain standard inline formatting
+(italics, links, footnotes, etc.).
+.PP
+Title blocks will always be parsed, but they will affect the output only
+when the \f[C]\-\-standalone\f[] (\f[C]\-s\f[]) option is chosen.
+In HTML output, titles will appear twice: once in the document head \-\-
+this is the title that will appear at the top of the window in a browser
+\-\- and once at the beginning of the document body.
+The title in the document head can have an optional prefix attached
+(\f[C]\-\-title\-prefix\f[] or \f[C]\-T\f[] option).
+The title in the body appears as an H1 element with class "title", so it
+can be suppressed or reformatted with CSS.
+If a title prefix is specified with \f[C]\-T\f[] and no title block
+appears in the document, the title prefix will be used by itself as the
+HTML title.
+.PP
+The man page writer extracts a title, man page section number, and other
+header and footer information from the title line.
+The title is assumed to be the first word on the title line, which may
+optionally end with a (single\-digit) section number in parentheses.
+(There should be no space between the title and the parentheses.)
+Anything after this is assumed to be additional footer and header text.
+A single pipe character (\f[C]|\f[]) should be used to separate the
+footer text from the header text.
+Thus,
+.IP
+.nf
+\f[C]
+%\ PANDOC(1)
+\f[]
+.fi
+.PP
+will yield a man page with the title \f[C]PANDOC\f[] and section 1.
+.IP
+.nf
+\f[C]
+%\ PANDOC(1)\ Pandoc\ User\ Manuals
+\f[]
+.fi
+.PP
+will also have "Pandoc User Manuals" in the footer.
+.IP
+.nf
+\f[C]
+%\ PANDOC(1)\ Pandoc\ User\ Manuals\ |\ Version\ 4.0
+\f[]
+.fi
+.PP
+will also have "Version 4.0" in the header.
+.SS Extension: \f[C]yaml_metadata_block\f[]
+.PP
+A YAML metadata block is a valid YAML object, delimited by a line of
+three hyphens (\f[C]\-\-\-\f[]) at the top and a line of three hyphens
+(\f[C]\-\-\-\f[]) or three dots (\f[C]\&...\f[]) at the bottom.
+A YAML metadata block may occur anywhere in the document, but if it is
+not at the beginning, it must be preceded by a blank line.
+(Note that, because of the way pandoc concatenates input files when
+several are provided, you may also keep the metadata in a separate YAML
+file and pass it to pandoc as an argument, along with your markdown
+files:
+.IP
+.nf
+\f[C]
+pandoc\ chap1.md\ chap2.md\ chap3.md\ metadata.yaml\ \-s\ \-o\ book.html
+\f[]
+.fi
+.PP
+Just be sure that the YAML file begins with \f[C]\-\-\-\f[] and ends
+with \f[C]\-\-\-\f[] or \f[C]\&...\f[].)
+.PP
+Metadata will be taken from the fields of the YAML object and added to
+any existing document metadata.
+Metadata can contain lists and objects (nested arbitrarily), but all
+string scalars will be interpreted as markdown.
+Fields with names ending in an underscore will be ignored by pandoc.
+(They may be given a role by external processors.)
+.PP
+A document may contain multiple metadata blocks.
+The metadata fields will be combined through a \f[I]left\-biased
+union\f[]: if two metadata blocks attempt to set the same field, the
+value from the first block will be taken.
+.PP
+When pandoc is used with \f[C]\-t\ markdown\f[] to create a markdown
+document, a YAML metadata block will be produced only if the
+\f[C]\-s/\-\-standalone\f[] option is used.
+All of the metadata will appear in a single block at the beginning of
+the document.
+.PP
+Note that YAML escaping rules must be followed.
+Thus, for example, if a title contains a colon, it must be quoted.
+The pipe character (\f[C]|\f[]) can be used to begin an indented block
+that will be interpreted literally, without need for escaping.
+This form is necessary when the field contains blank lines:
+.IP
+.nf
+\f[C]
+\-\-\-
+title:\ \ \[aq]This\ is\ the\ title:\ it\ contains\ a\ colon\[aq]
+author:
+\-\ name:\ Author\ One
+\ \ affiliation:\ University\ of\ Somewhere
+\-\ name:\ Author\ Two
+\ \ affiliation:\ University\ of\ Nowhere
+tags:\ [nothing,\ nothingness]
+abstract:\ |
+\ \ This\ is\ the\ abstract.
+
+\ \ It\ consists\ of\ two\ paragraphs.
+\&...
+\f[]
+.fi
+.PP
+Template variables will be set automatically from the metadata.
+Thus, for example, in writing HTML, the variable \f[C]abstract\f[] will
+be set to the HTML equivalent of the markdown in the \f[C]abstract\f[]
+field:
+.IP
+.nf
+\f[C]
+<p>This\ is\ the\ abstract.</p>
+<p>It\ consists\ of\ two\ paragraphs.</p>
+\f[]
+.fi
+.PP
+Note: The \f[C]author\f[] variable in the default templates expects a
+simple list or string.
+To use the structured authors in the example, you would need a custom
+template.
+For example:
+.IP
+.nf
+\f[C]
+$for(author)$
+$if(author.name)$
+$author.name$$if(author.affiliation)$\ ($author.affiliation$)$endif$
+$else$
+$author$
+$endif$
+$endfor$
+\f[]
+.fi
+.SS Backslash escapes
+.SS Extension: \f[C]all_symbols_escapable\f[]
+.PP
+Except inside a code block or inline code, any punctuation or space
+character preceded by a backslash will be treated literally, even if it
+would normally indicate formatting.
+Thus, for example, if one writes
+.IP
+.nf
+\f[C]
+*\\*hello\\**
+\f[]
+.fi
+.PP
+one will get
+.IP
+.nf
+\f[C]
+<em>*hello*</em>
+\f[]
+.fi
+.PP
+instead of
+.IP
+.nf
+\f[C]
+<strong>hello</strong>
+\f[]
+.fi
+.PP
+This rule is easier to remember than standard markdown\[aq]s rule, which
+allows only the following characters to be backslash\-escaped:
+.IP
+.nf
+\f[C]
+\\`*_{}[]()>#+\-.!
+\f[]
+.fi
+.PP
+(However, if the \f[C]markdown_strict\f[] format is used, the standard
+markdown rule will be used.)
+.PP
+A backslash\-escaped space is parsed as a nonbreaking space.
+It will appear in TeX output as \f[C]~\f[] and in HTML and XML as
+\f[C]\\&#160;\f[] or \f[C]\\&nbsp;\f[].
+.PP
+A backslash\-escaped newline (i.e.
+a backslash occurring at the end of a line) is parsed as a hard line
+break.
+It will appear in TeX output as \f[C]\\\\\f[] and in HTML as
+\f[C]<br\ />\f[].
+This is a nice alternative to markdown\[aq]s "invisible" way of
+indicating hard line breaks using two trailing spaces on a line.
+.PP
+Backslash escapes do not work in verbatim contexts.
+.SS Smart punctuation
+.SS Extension
+.PP
+If the \f[C]\-\-smart\f[] option is specified, pandoc will produce
+typographically correct output, converting straight quotes to curly
+quotes, \f[C]\-\-\-\f[] to em\-dashes, \f[C]\-\-\f[] to en\-dashes, and
+\f[C]\&...\f[] to ellipses.
+Nonbreaking spaces are inserted after certain abbreviations, such as
+"Mr."
+.PP
+Note: if your LaTeX template uses the \f[C]csquotes\f[] package, pandoc
+will detect automatically this and use \f[C]\\enquote{...}\f[] for
+quoted text.
+.SS Inline formatting
+.SS Emphasis
+.PP
+To \f[I]emphasize\f[] some text, surround it with \f[C]*\f[]s or
+\f[C]_\f[], like this:
+.IP
+.nf
+\f[C]
+This\ text\ is\ _emphasized\ with\ underscores_,\ and\ this
+is\ *emphasized\ with\ asterisks*.
+\f[]
+.fi
+.PP
+Double \f[C]*\f[] or \f[C]_\f[] produces \f[B]strong emphasis\f[]:
+.IP
+.nf
+\f[C]
+This\ is\ **strong\ emphasis**\ and\ __with\ underscores__.
+\f[]
+.fi
+.PP
+A \f[C]*\f[] or \f[C]_\f[] character surrounded by spaces, or
+backslash\-escaped, will not trigger emphasis:
+.IP
+.nf
+\f[C]
+This\ is\ *\ not\ emphasized\ *,\ and\ \\*neither\ is\ this\\*.
+\f[]
+.fi
+.SS Extension: \f[C]intraword_underscores\f[]
+.PP
+Because \f[C]_\f[] is sometimes used inside words and identifiers,
+pandoc does not interpret a \f[C]_\f[] surrounded by alphanumeric
+characters as an emphasis marker.
+If you want to emphasize just part of a word, use \f[C]*\f[]:
+.IP
+.nf
+\f[C]
+feas*ible*,\ not\ feas*able*.
+\f[]
+.fi
+.SS Strikeout
+.SS Extension: \f[C]strikeout\f[]
+.PP
+To strikeout a section of text with a horizontal line, begin and end it
+with \f[C]~~\f[].
+Thus, for example,
+.IP
+.nf
+\f[C]
+This\ ~~is\ deleted\ text.~~
+\f[]
+.fi
+.SS Superscripts and subscripts
+.SS Extension: \f[C]superscript\f[], \f[C]subscript\f[]
+.PP
+Superscripts may be written by surrounding the superscripted text by
+\f[C]^\f[] characters; subscripts may be written by surrounding the
+subscripted text by \f[C]~\f[] characters.
+Thus, for example,
+.IP
+.nf
+\f[C]
+H~2~O\ is\ a\ liquid.\ \ 2^10^\ is\ 1024.
+\f[]
+.fi
+.PP
+If the superscripted or subscripted text contains spaces, these spaces
+must be escaped with backslashes.
+(This is to prevent accidental superscripting and subscripting through
+the ordinary use of \f[C]~\f[] and \f[C]^\f[].) Thus, if you want the
+letter P with \[aq]a cat\[aq] in subscripts, use \f[C]P~a\\\ cat~\f[],
+not \f[C]P~a\ cat~\f[].
+.SS Verbatim
+.PP
+To make a short span of text verbatim, put it inside backticks:
+.IP
+.nf
+\f[C]
+What\ is\ the\ difference\ between\ `>>=`\ and\ `>>`?
+\f[]
+.fi
+.PP
+If the verbatim text includes a backtick, use double backticks:
+.IP
+.nf
+\f[C]
+Here\ is\ a\ literal\ backtick\ ``\ `\ ``.
+\f[]
+.fi
+.PP
+(The spaces after the opening backticks and before the closing backticks
+will be ignored.)
+.PP
+The general rule is that a verbatim span starts with a string of
+consecutive backticks (optionally followed by a space) and ends with a
+string of the same number of backticks (optionally preceded by a space).
+.PP
+Note that backslash\-escapes (and other markdown constructs) do not work
+in verbatim contexts:
+.IP
+.nf
+\f[C]
+This\ is\ a\ backslash\ followed\ by\ an\ asterisk:\ `\\*`.
+\f[]
+.fi
+.SS Extension: \f[C]inline_code_attributes\f[]
+.PP
+Attributes can be attached to verbatim text, just as with fenced code
+blocks:
+.IP
+.nf
+\f[C]
+`<$>`{.haskell}
+\f[]
+.fi
+.SS Small caps
+.PP
+To write small caps, you can use an HTML span tag:
+.IP
+.nf
+\f[C]
+<span\ style="font\-variant:small\-caps;">Small\ caps</span>
+\f[]
+.fi
+.PP
+(The semicolon is optional and there may be space after the colon.) This
+will work in all output formats that support small caps.
+.SS Math
+.SS Extension: \f[C]tex_math_dollars\f[]
+.PP
+Anything between two \f[C]$\f[] characters will be treated as TeX math.
+The opening \f[C]$\f[] must have a non\-space character immediately to
+its right, while the closing \f[C]$\f[] must have a non\-space character
+immediately to its left, and must not be followed immediately by a
+digit.
+Thus, \f[C]$20,000\ and\ $30,000\f[] won\[aq]t parse as math.
+If for some reason you need to enclose text in literal \f[C]$\f[]
+characters, backslash\-escape them and they won\[aq]t be treated as math
+delimiters.
+.PP
+TeX math will be printed in all output formats.
+How it is rendered depends on the output format:
+.TP
+.B Markdown, LaTeX, Org\-Mode, ConTeXt
+It will appear verbatim between \f[C]$\f[] characters.
+.RS
+.RE
+.TP
+.B reStructuredText
+It will be rendered using an interpreted text role \f[C]:math:\f[], as
+described here
+.RS
+.RE
+.TP
+.B AsciiDoc
+It will be rendered as \f[C]latexmath:[...]\f[].
+.RS
+.RE
+.TP
+.B Texinfo
+It will be rendered inside a \f[C]\@math\f[] command.
+.RS
+.RE
+.TP
+.B groff man
+It will be rendered verbatim without \f[C]$\f[]\[aq]s.
+.RS
+.RE
+.TP
+.B MediaWiki, DokuWiki
+It will be rendered inside \f[C]<math>\f[] tags.
+.RS
+.RE
+.TP
+.B Textile
+It will be rendered inside \f[C]<span\ class="math">\f[] tags.
+.RS
+.RE
+.TP
+.B RTF, OpenDocument, ODT
+It will be rendered, if possible, using unicode characters, and will
+otherwise appear verbatim.
+.RS
+.RE
+.TP
+.B Docbook
+If the \f[C]\-\-mathml\f[] flag is used, it will be rendered using
+mathml in an \f[C]inlineequation\f[] or \f[C]informalequation\f[] tag.
+Otherwise it will be rendered, if possible, using unicode characters.
+.RS
+.RE
+.TP
+.B Docx
+It will be rendered using OMML math markup.
+.RS
+.RE
+.TP
+.B FictionBook2
+If the \f[C]\-\-webtex\f[] option is used, formulas are rendered as
+images using Google Charts or other compatible web service, downloaded
+and embedded in the e\-book.
+Otherwise, they will appear verbatim.
+.RS
+.RE
+.TP
+.B HTML, Slidy, DZSlides, S5, EPUB
+The way math is rendered in HTML will depend on the command\-line
+options selected:
+.RS
+.IP "1." 3
+The default is to render TeX math as far as possible using unicode
+characters, as with RTF, DocBook, and OpenDocument output.
+Formulas are put inside a \f[C]span\f[] with \f[C]class="math"\f[], so
+that they may be styled differently from the surrounding text if needed.
+.IP "2." 3
+If the \f[C]\-\-latexmathml\f[] option is used, TeX math will be
+displayed between \f[C]$\f[] or \f[C]$$\f[] characters and put in
+\f[C]<span>\f[] tags with class \f[C]LaTeX\f[].
+The LaTeXMathML script will be used to render it as formulas.
+(This trick does not work in all browsers, but it works in Firefox.
+In browsers that do not support LaTeXMathML, TeX math will appear
+verbatim between \f[C]$\f[] characters.)
+.IP "3." 3
+If the \f[C]\-\-jsmath\f[] option is used, TeX math will be put inside
+\f[C]<span>\f[] tags (for inline math) or \f[C]<div>\f[] tags (for
+display math) with class \f[C]math\f[].
+The jsMath script will be used to render it.
+.IP "4." 3
+If the \f[C]\-\-mimetex\f[] option is used, the mimeTeX CGI script will
+be called to generate images for each TeX formula.
+This should work in all browsers.
+The \f[C]\-\-mimetex\f[] option takes an optional URL as argument.
+If no URL is specified, it will be assumed that the mimeTeX CGI script
+is at \f[C]/cgi\-bin/mimetex.cgi\f[].
+.IP "5." 3
+If the \f[C]\-\-gladtex\f[] option is used, TeX formulas will be
+enclosed in \f[C]<eq>\f[] tags in the HTML output.
+The resulting \f[C]htex\f[] file may then be processed by gladTeX, which
+will produce image files for each formula and an \f[C]html\f[] file with
+links to these images.
+So, the procedure is:
+.RS 4
+.IP
+.nf
+\f[C]
+pandoc\ \-s\ \-\-gladtex\ myfile.txt\ \-o\ myfile.htex
+gladtex\ \-d\ myfile\-images\ myfile.htex
+#\ produces\ myfile.html\ and\ images\ in\ myfile\-images
+\f[]
+.fi
+.RE
+.IP "6." 3
+If the \f[C]\-\-webtex\f[] option is used, TeX formulas will be
+converted to \f[C]<img>\f[] tags that link to an external script that
+converts formulas to images.
+The formula will be URL\-encoded and concatenated with the URL provided.
+If no URL is specified, the Google Chart API will be used
+(\f[C]http://chart.apis.google.com/chart?cht=tx&chl=\f[]).
+.IP "7." 3
+If the \f[C]\-\-mathjax\f[] option is used, TeX math will be displayed
+between \f[C]\\(...\\)\f[] (for inline math) or \f[C]\\[...\\]\f[] (for
+display math) and put in \f[C]<span>\f[] tags with class \f[C]math\f[].
+The MathJax script will be used to render it as formulas.
+.RE
+.SS Raw HTML
+.SS Extension: \f[C]raw_html\f[]
+.PP
+Markdown allows you to insert raw HTML (or DocBook) anywhere in a
+document (except verbatim contexts, where \f[C]<\f[], \f[C]>\f[], and
+\f[C]&\f[] are interpreted literally).
+(Technically this is not an extension, since standard markdown allows
+it, but it has been made an extension so that it can be disabled if
+desired.)
+.PP
+The raw HTML is passed through unchanged in HTML, S5, Slidy, Slideous,
+DZSlides, EPUB, Markdown, and Textile output, and suppressed in other
+formats.
+.SS Extension: \f[C]markdown_in_html_blocks\f[]
+.PP
+Standard markdown allows you to include HTML "blocks": blocks of HTML
+between balanced tags that are separated from the surrounding text with
+blank lines, and start and end at the left margin.
+Within these blocks, everything is interpreted as HTML, not markdown; so
+(for example), \f[C]*\f[] does not signify emphasis.
+.PP
+Pandoc behaves this way when the \f[C]markdown_strict\f[] format is
+used; but by default, pandoc interprets material between HTML block tags
+as markdown.
+Thus, for example, Pandoc will turn
+.IP
+.nf
+\f[C]
+<table>
+<tr>
+<td>*one*</td>
+<td>[a\ link](http://google.com)</td>
+</tr>
+</table>
+\f[]
+.fi
+.PP
+into
+.IP
+.nf
+\f[C]
+<table>
+<tr>
+<td><em>one</em></td>
+<td><a\ href="http://google.com">a\ link</a></td>
+</tr>
+</table>
+\f[]
+.fi
+.PP
+whereas \f[C]Markdown.pl\f[] will preserve it as is.
+.PP
+There is one exception to this rule: text between \f[C]<script>\f[] and
+\f[C]<style>\f[] tags is not interpreted as markdown.
+.PP
+This departure from standard markdown should make it easier to mix
+markdown with HTML block elements.
+For example, one can surround a block of markdown text with
+\f[C]<div>\f[] tags without preventing it from being interpreted as
+markdown.
+.SS Extension: \f[C]native_divs\f[]
+.PP
+Use native pandoc \f[C]Div\f[] blocks for content inside \f[C]<div>\f[]
+tags.
+For the most part this should give the same output as
+\f[C]markdown_in_html_blocks\f[], but it makes it easier to write pandoc
+filters to manipulate groups of blocks.
+.SS Extension: \f[C]native_spans\f[]
+.PP
+Use native pandoc \f[C]Span\f[] blocks for content inside
+\f[C]<span>\f[] tags.
+For the most part this should give the same output as \f[C]raw_html\f[],
+but it makes it easier to write pandoc filters to manipulate groups of
+inlines.
+.SS Raw TeX
+.SS Extension: \f[C]raw_tex\f[]
+.PP
+In addition to raw HTML, pandoc allows raw LaTeX, TeX, and ConTeXt to be
+included in a document.
+Inline TeX commands will be preserved and passed unchanged to the LaTeX
+and ConTeXt writers.
+Thus, for example, you can use LaTeX to include BibTeX citations:
+.IP
+.nf
+\f[C]
+This\ result\ was\ proved\ in\ \\cite{jones.1967}.
+\f[]
+.fi
+.PP
+Note that in LaTeX environments, like
+.IP
+.nf
+\f[C]
+\\begin{tabular}{|l|l|}\\hline
+Age\ &\ Frequency\ \\\\\ \\hline
+18\-\-25\ \ &\ 15\ \\\\
+26\-\-35\ \ &\ 33\ \\\\
+36\-\-45\ \ &\ 22\ \\\\\ \\hline
+\\end{tabular}
+\f[]
+.fi
+.PP
+the material between the begin and end tags will be interpreted as raw
+LaTeX, not as markdown.
+.PP
+Inline LaTeX is ignored in output formats other than Markdown, LaTeX,
+and ConTeXt.
+.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.
+So, for example, the following will work in all output formats, not just
+LaTeX:
+.PP
+⟨\f[I]a\f[], \f[I]b\f[], \f[I]c\f[]⟩
+.PP
+In LaTeX output, the \f[C]\\newcommand\f[] definition will simply be
+passed unchanged to the output.
+.SS Links
+.PP
+Markdown allows links to be specified in several ways.
+.SS Automatic links
+.PP
+If you enclose a URL or email address in pointy brackets, it will become
+a link:
+.IP
+.nf
+\f[C]
+<http://google.com>
+<sam\@green.eggs.ham>
+\f[]
+.fi
+.SS Inline links
+.PP
+An inline link consists of the link text in square brackets, followed by
+the URL in parentheses.
+(Optionally, the URL can be followed by a link title, in quotes.)
+.IP
+.nf
+\f[C]
+This\ is\ an\ [inline\ link](/url),\ and\ here\[aq]s\ [one\ with
+a\ title](http://fsf.org\ "click\ here\ for\ a\ good\ time!").
+\f[]
+.fi
+.PP
+There can be no space between the bracketed part and the parenthesized
+part.
+The link text can contain formatting (such as emphasis), but the title
+cannot.
+.PP
+Email addresses in inline links are not autodetected, so they have to be
+prefixed with \f[C]mailto\f[]:
+.IP
+.nf
+\f[C]
+[Write\ me!](mailto:sam\@green.eggs.ham)
+\f[]
+.fi
+.SS Reference links
+.PP
+An \f[I]explicit\f[] reference link has two parts, the link itself and
+the link definition, which may occur elsewhere in the document (either
+before or after the link).
+.PP
+The link consists of link text in square brackets, followed by a label
+in square brackets.
+(There can be space between the two.) The link definition consists of
+the bracketed label, followed by a colon and a space, followed by the
+URL, and optionally (after a space) a link title either in quotes or in
+parentheses.
+The label must not be parseable as a citation (assuming the
+\f[C]citations\f[] extension is enabled): citations take precedence over
+link labels.
+.PP
+Here are some examples:
+.IP
+.nf
+\f[C]
+[my\ label\ 1]:\ /foo/bar.html\ \ "My\ title,\ optional"
+[my\ label\ 2]:\ /foo
+[my\ label\ 3]:\ http://fsf.org\ (The\ free\ software\ foundation)
+[my\ label\ 4]:\ /bar#special\ \ \[aq]A\ title\ in\ single\ quotes\[aq]
+\f[]
+.fi
+.PP
+The URL may optionally be surrounded by angle brackets:
+.IP
+.nf
+\f[C]
+[my\ label\ 5]:\ <http://foo.bar.baz>
+\f[]
+.fi
+.PP
+The title may go on the next line:
+.IP
+.nf
+\f[C]
+[my\ label\ 3]:\ http://fsf.org
+\ \ "The\ free\ software\ foundation"
+\f[]
+.fi
+.PP
+Note that link labels are not case sensitive.
+So, this will work:
+.IP
+.nf
+\f[C]
+Here\ is\ [my\ link][FOO]
+
+[Foo]:\ /bar/baz
+\f[]
+.fi
+.PP
+In an \f[I]implicit\f[] reference link, the second pair of brackets is
+empty:
+.IP
+.nf
+\f[C]
+See\ [my\ website][].
+
+[my\ website]:\ http://foo.bar.baz
+\f[]
+.fi
+.PP
+Note: In \f[C]Markdown.pl\f[] and most other markdown implementations,
+reference link definitions cannot occur in nested constructions such as
+list items or block quotes.
+Pandoc lifts this arbitrary seeming restriction.
+So the following is fine in pandoc, though not in most other
+implementations:
+.IP
+.nf
+\f[C]
+>\ My\ block\ [quote].
+>
+>\ [quote]:\ /foo
+\f[]
+.fi
+.SS Extension: \f[C]shortcut_reference_links\f[]
+.PP
+In a \f[I]shortcut\f[] reference link, the second pair of brackets may
+be omitted entirely:
+.IP
+.nf
+\f[C]
+See\ [my\ website].
+
+[my\ website]:\ http://foo.bar.baz
+\f[]
+.fi
+.SS Internal links
+.PP
+To link to another section of the same document, use the automatically
+generated identifier (see Header identifiers, below).
+For example:
+.IP
+.nf
+\f[C]
+See\ the\ [Introduction](#introduction).
+\f[]
+.fi
+.PP
+or
+.IP
+.nf
+\f[C]
+See\ the\ [Introduction].
+
+[Introduction]:\ #introduction
+\f[]
+.fi
+.PP
+Internal links are currently supported for HTML formats (including HTML
+slide shows and EPUB), LaTeX, and ConTeXt.
+.SS Images
+.PP
+A link immediately preceded by a \f[C]!\f[] will be treated as an image.
+The link text will be used as the image\[aq]s alt text:
+.IP
+.nf
+\f[C]
+![la\ lune](lalune.jpg\ "Voyage\ to\ the\ moon")
+
+![movie\ reel]
+
+[movie\ reel]:\ movie.gif
+\f[]
+.fi
+.SS Extension: \f[C]implicit_figures\f[]
+.PP
+An image occurring by itself in a paragraph will be rendered as a figure
+with a caption. (In LaTeX, a figure environment will be used; in HTML,
+the image will be placed in a \f[C]div\f[] with class \f[C]figure\f[],
+together with a caption in a \f[C]p\f[] with class \f[C]caption\f[].)
+The image\[aq]s alt text will be used as the caption.
+.IP
+.nf
+\f[C]
+![This\ is\ the\ caption](/url/of/image.png)
+\f[]
+.fi
+.PP
+If you just want a regular inline image, just make sure it is not the
+only thing in the paragraph.
+One way to do this is to insert a nonbreaking space after the image:
+.IP
+.nf
+\f[C]
+![This\ image\ won\[aq]t\ be\ a\ figure](/url/of/image.png)\\
+\f[]
+.fi
+.SS Footnotes
+.SS Extension: \f[C]footnotes\f[]
+.PP
+Pandoc\[aq]s markdown allows footnotes, using the following syntax:
+.IP
+.nf
+\f[C]
+Here\ is\ a\ footnote\ reference,[^1]\ and\ another.[^longnote]
+
+[^1]:\ Here\ is\ the\ footnote.
+
+[^longnote]:\ Here\[aq]s\ one\ with\ multiple\ blocks.
+
+\ \ \ \ Subsequent\ paragraphs\ are\ indented\ to\ show\ that\ they
+belong\ to\ the\ previous\ footnote.
+
+\ \ \ \ \ \ \ \ {\ some.code\ }
+
+\ \ \ \ The\ whole\ paragraph\ can\ be\ indented,\ or\ just\ the\ first
+\ \ \ \ line.\ \ In\ this\ way,\ multi\-paragraph\ footnotes\ work\ like
+\ \ \ \ multi\-paragraph\ list\ items.
+
+This\ paragraph\ won\[aq]t\ be\ part\ of\ the\ note,\ because\ it
+isn\[aq]t\ indented.
+\f[]
+.fi
+.PP
+The identifiers in footnote references may not contain spaces, tabs, or
+newlines.
+These identifiers are used only to correlate the footnote reference with
+the note itself; in the output, footnotes will be numbered sequentially.
+.PP
+The footnotes themselves need not be placed at the end of the document.
+They may appear anywhere except inside other block elements (lists,
+block quotes, tables, etc.).
+.SS Extension: \f[C]inline_notes\f[]
+.PP
+Inline footnotes are also allowed (though, unlike regular notes, they
+cannot contain multiple paragraphs).
+The syntax is as follows:
+.IP
+.nf
+\f[C]
+Here\ is\ an\ inline\ note.^[Inlines\ notes\ are\ easier\ to\ write,\ since
+you\ don\[aq]t\ have\ to\ pick\ an\ identifier\ and\ move\ down\ to\ type\ the
+note.]
+\f[]
+.fi
+.PP
+Inline and regular footnotes may be mixed freely.
+.SS Citations
+.SS Extension: \f[C]citations\f[]
+.PP
+Using an external filter, \f[C]pandoc\-citeproc\f[], pandoc can
+automatically generate citations and a bibliography in a number of
+styles.
+Basic usage is
+.IP
+.nf
+\f[C]
+pandoc\ \-\-filter\ pandoc\-citeproc\ myinput.txt
+\f[]
+.fi
+.PP
+In order to use this feature, you will need to specify a bibliography
+file using the \f[C]bibliography\f[] metadata field in a YAML metadata
+section, or \f[C]\-\-bibliography\f[] command line argument.
+You can supply multiple \f[C]\-\-bibliography\f[] arguments or set
+\f[C]bibliography\f[] metadata field to YAML array, if you want to use
+multiple bibliography files.
+The bibliography may have any of these formats:
+.PP
+.TS
+tab(@);
+l l.
+T{
+Format
+T}@T{
+File extension
+T}
+_
+T{
+BibLaTeX
+T}@T{
+\&.bib
+T}
+T{
+BibTeX
+T}@T{
+\&.bibtex
+T}
+T{
+Copac
+T}@T{
+\&.copac
+T}
+T{
+CSL JSON
+T}@T{
+\&.json
+T}
+T{
+CSL YAML
+T}@T{
+\&.yaml
+T}
+T{
+EndNote
+T}@T{
+\&.enl
+T}
+T{
+EndNote XML
+T}@T{
+\&.xml
+T}
+T{
+ISI
+T}@T{
+\&.wos
+T}
+T{
+MEDLINE
+T}@T{
+\&.medline
+T}
+T{
+MODS
+T}@T{
+\&.mods
+T}
+T{
+RIS
+T}@T{
+\&.ris
+T}
+.TE
+.PP
+Note that \f[C]\&.bib\f[] can generally be used with both BibTeX and
+BibLaTeX files, but you can use \f[C]\&.bibtex\f[] to force BibTeX.
+.PP
+Note that \f[C]pandoc\-citeproc\ \-\-bib2json\f[] and
+\f[C]pandoc\-citeproc\ \-\-bib2yaml\f[] can produce \f[C]\&.json\f[] and
+\f[C]\&.yaml\f[] files from any of the supported formats.
+.PP
+In\-field markup: In bibtex and biblatex databases, pandoc\-citeproc
+parses (a subset of) LaTeX markup; in CSL JSON databases, an HTML\-like
+markup (specs); and in CSL YAML databases, pandoc markdown.
+\f[C]pandoc\-citeproc\ \-j\f[] and \f[C]\-y\f[] interconvert these
+markup formats as far as possible.
+.PP
+As an alternative to specifying a bibliography file, you can include the
+citation data directly in the \f[C]references\f[] field of the
+document\[aq]s YAML metadata.
+The field should contain an array of YAML\-encoded references, for
+example:
+.IP
+.nf
+\f[C]
+\-\-\-
+references:
+\-\ type:\ article\-journal
+\ \ id:\ WatsonCrick1953
+\ \ author:
+\ \ \-\ family:\ Watson
+\ \ \ \ given:\ J.\ D.
+\ \ \-\ family:\ Crick
+\ \ \ \ given:\ F.\ H.\ C.
+\ \ issued:
+\ \ \ \ date\-parts:
+\ \ \ \ \-\ \-\ 1953
+\ \ \ \ \ \ \-\ 4
+\ \ \ \ \ \ \-\ 25
+\ \ title:\ \[aq]Molecular\ structure\ of\ nucleic\ acids:\ a\ structure\ for\ deoxyribose
+\ \ \ \ nucleic\ acid\[aq]
+\ \ title\-short:\ Molecular\ structure\ of\ nucleic\ acids
+\ \ container\-title:\ Nature
+\ \ volume:\ 171
+\ \ issue:\ 4356
+\ \ page:\ 737\-738
+\ \ DOI:\ 10.1038/171737a0
+\ \ URL:\ http://www.nature.com/nature/journal/v171/n4356/abs/171737a0.html
+\ \ language:\ en\-GB
+\&...
+\f[]
+.fi
+.PP
+(\f[C]pandoc\-citeproc\ \-\-bib2yaml\f[] can produce these from a
+bibliography file in one of the supported formats.)
+.PP
+By default, \f[C]pandoc\-citeproc\f[] will use the Chicago Manual of
+Style author\-date format for citations and references.
+To use another style, you will need to specify a CSL 1.0 style file in
+the \f[C]csl\f[] metadata field.
+A repository of CSL styles can be found at
+https://github.com/citation\-style\-language/styles.
+See also http://zotero.org/styles for easy browsing.
+A primer on creating and modifying CSL styles can be found at
+http://citationstyles.org/downloads/primer.html.
+.PP
+Citations go inside square brackets and are separated by semicolons.
+Each citation must have a key, composed of \[aq]\@\[aq] + the citation
+identifier from the database, and may optionally have a prefix, a
+locator, and a suffix.
+The citation key must begin with a letter, digit, or \f[C]_\f[], and may
+contain alphanumerics, \f[C]_\f[], and internal punctuation characters
+(\f[C]:.#$%&\-+?<>~/\f[]).
+Here are some examples:
+.IP
+.nf
+\f[C]
+Blah\ blah\ [see\ \@doe99,\ pp.\ 33\-35;\ also\ \@smith04,\ ch.\ 1].
+
+Blah\ blah\ [\@doe99,\ pp.\ 33\-35,\ 38\-39\ and\ *passim*].
+
+Blah\ blah\ [\@smith04;\ \@doe99].
+\f[]
+.fi
+.PP
+A minus sign (\f[C]\-\f[]) before the \f[C]\@\f[] will suppress mention
+of the author in the citation.
+This can be useful when the author is already mentioned in the text:
+.IP
+.nf
+\f[C]
+Smith\ says\ blah\ [\-\@smith04].
+\f[]
+.fi
+.PP
+You can also write an in\-text citation, as follows:
+.IP
+.nf
+\f[C]
+\@smith04\ says\ blah.
+
+\@smith04\ [p.\ 33]\ says\ blah.
+\f[]
+.fi
+.PP
+If the style calls for a list of works cited, it will be placed at the
+end of the document.
+Normally, you will want to end your document with an appropriate header:
+.IP
+.nf
+\f[C]
+last\ paragraph...
+
+#\ References
+\f[]
+.fi
+.PP
+The bibliography will be inserted after this header.
+Note that the \f[C]unnumbered\f[] class will be added to this header, so
+that the section will not be numbered.
+.PP
+If you want to include items in the bibliography without actually citing
+them in the body text, you can define a dummy \f[C]nocite\f[] metadata
+field and put the citations there:
+.IP
+.nf
+\f[C]
+\-\-\-
+nocite:\ |
+\ \ \@item1,\ \@item2
+\&...
+
+\@item3
+\f[]
+.fi
+.PP
+In this example, the document will contain a citation for \f[C]item3\f[]
+only, but the bibliography will contain entries for \f[C]item1\f[],
+\f[C]item2\f[], and \f[C]item3\f[].
+.PP
+For LaTeX or PDF output, you can also use NatBib or BibLaTeX to render
+bibliography.
+In order to do so, specify bibliography files as outlined above, and add
+\f[C]\-\-natbib\f[] or \f[C]\-\-biblatex\f[] argument to \f[C]pandoc\f[]
+invocation.
+Bear in mind that bibliography files have to be in respective format
+(either BibTeX or BibLaTeX).
+.SS Non\-pandoc extensions
+.PP
+The following markdown syntax extensions are not enabled by default in
+pandoc, but may be enabled by adding \f[C]+EXTENSION\f[] to the format
+name, where \f[C]EXTENSION\f[] is the name of the extension.
+Thus, for example, \f[C]markdown+hard_line_breaks\f[] is markdown with
+hard line breaks.
+.SS Extension: \f[C]lists_without_preceding_blankline\f[]
+.PP
+Allow a list to occur right after a paragraph, with no intervening blank
+space.
+.SS Extension: \f[C]hard_line_breaks\f[]
+.PP
+Causes all newlines within a paragraph to be interpreted as hard line
+breaks instead of spaces.
+.SS Extension: \f[C]ignore_line_breaks\f[]
+.PP
+Causes newlines within a paragraph to be ignored, rather than being
+treated as spaces or as hard line breaks.
+This option is intended for use with East Asian languages where spaces
+are not used between words, but text is divided into lines for
+readability.
+.SS Extension: \f[C]tex_math_single_backslash\f[]
+.PP
+Causes anything between \f[C]\\(\f[] and \f[C]\\)\f[] to be interpreted
+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[].
+.SS Extension: \f[C]tex_math_double_backslash\f[]
+.PP
+Causes anything between \f[C]\\\\(\f[] and \f[C]\\\\)\f[] to be
+interpreted as inline TeX math, and anything between \f[C]\\\\[\f[] and
+\f[C]\\\\]\f[] to be interpreted as display TeX math.
+.SS Extension: \f[C]markdown_attribute\f[]
+.PP
+By default, pandoc interprets material inside block\-level tags as
+markdown.
+This extension changes the behavior so that markdown is only parsed
+inside block\-level tags if the tags have the attribute
+\f[C]markdown=1\f[].
+.SS Extension: \f[C]mmd_title_block\f[]
+.PP
+Enables a MultiMarkdown style title block at the top of the document,
+for example:
+.IP
+.nf
+\f[C]
+Title:\ \ \ My\ title
+Author:\ \ John\ Doe
+Date:\ \ \ \ September\ 1,\ 2008
+Comment:\ This\ is\ a\ sample\ mmd\ title\ block,\ with
+\ \ \ \ \ \ \ \ \ a\ field\ spanning\ multiple\ lines.
+\f[]
+.fi
+.PP
+See the MultiMarkdown documentation for details.
+If \f[C]pandoc_title_block\f[] or \f[C]yaml_metadata_block\f[] is
+enabled, it will take precedence over \f[C]mmd_title_block\f[].
+.SS Extension: \f[C]abbreviations\f[]
+.PP
+Parses PHP Markdown Extra abbreviation keys, like
+.IP
+.nf
+\f[C]
+*[HTML]:\ Hyper\ Text\ Markup\ Language
+\f[]
+.fi
+.PP
+Note that the pandoc document model does not support abbreviations, so
+if this extension is enabled, abbreviation keys are simply skipped (as
+opposed to being parsed as paragraphs).
+.SS Extension: \f[C]autolink_bare_uris\f[]
+.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]link_attributes\f[]
+.PP
+Parses multimarkdown style key\-value attributes on link and image
+references.
+Note that pandoc\[aq]s internal document model provides nowhere to put
+these, so they are presently just ignored.
+.SS Extension: \f[C]mmd_header_identifiers\f[]
+.PP
+Parses multimarkdown style header identifiers (in square brackets, after
+the header but before any trailing \f[C]#\f[]s in an ATX header).
+.SS Extension: \f[C]compact_definition_lists\f[]
+.PP
+Activates the definition list syntax of pandoc 1.12.x and earlier.
+This syntax differs from the one described above in several respects:
+.IP \[bu] 2
+No blank line is required between consecutive items of the definition
+list.
+.IP \[bu] 2
+To get a "tight" or "compact" list, omit space between consecutive
+items; the space between a term and its definition does not affect
+anything.
+.IP \[bu] 2
+Lazy wrapping of paragraphs is not allowed: the entire definition must
+be indented four spaces.
+.SS Markdown variants
+.PP
+In addition to pandoc\[aq]s extended markdown, the following markdown
+variants are supported:
+.TP
+.B \f[C]markdown_phpextra\f[] (PHP Markdown Extra)
+\f[C]footnotes\f[], \f[C]pipe_tables\f[], \f[C]raw_html\f[],
+\f[C]markdown_attribute\f[], \f[C]fenced_code_blocks\f[],
+\f[C]definition_lists\f[], \f[C]intraword_underscores\f[],
+\f[C]header_attributes\f[], \f[C]abbreviations\f[],
+\f[C]shortcut_reference_links\f[].
+.RS
+.RE
+.TP
+.B \f[C]markdown_github\f[] (GitHub\-flavored Markdown)
+\f[C]pipe_tables\f[], \f[C]raw_html\f[],
+\f[C]tex_math_single_backslash\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]shortcut_reference_links\f[].
+.RS
+.RE
+.TP
+.B \f[C]markdown_mmd\f[] (MultiMarkdown)
+\f[C]pipe_tables\f[] \f[C]raw_html\f[], \f[C]markdown_attribute\f[],
+\f[C]link_attributes\f[], \f[C]raw_tex\f[],
+\f[C]tex_math_double_backslash\f[], \f[C]intraword_underscores\f[],
+\f[C]mmd_title_block\f[], \f[C]footnotes\f[], \f[C]definition_lists\f[],
+\f[C]all_symbols_escapable\f[], \f[C]implicit_header_references\f[],
+\f[C]auto_identifiers\f[], \f[C]mmd_header_identifiers\f[],
+\f[C]shortcut_reference_links\f[].
+.RS
+.RE
+.TP
+.B \f[C]markdown_strict\f[] (Markdown.pl)
+\f[C]raw_html\f[]
+.RS
+.RE
+.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.)
+.SH PRODUCING SLIDE SHOWS WITH PANDOC
+.PP
+You can use Pandoc to produce an HTML + javascript slide presentation
+that can be viewed via a web browser.
+There are five ways to do this, using S5, DZSlides, Slidy, Slideous, or
+reveal.js.
+You can also produce a PDF slide show using LaTeX beamer.
+.PP
+Here\[aq]s the markdown source for a simple slide show,
+\f[C]habits.txt\f[]:
+.IP
+.nf
+\f[C]
+%\ Habits
+%\ John\ Doe
+%\ March\ 22,\ 2005
+
+#\ In\ the\ morning
+
+##\ Getting\ up
+
+\-\ Turn\ off\ alarm
+\-\ Get\ out\ of\ bed
+
+##\ Breakfast
+
+\-\ Eat\ eggs
+\-\ Drink\ coffee
+
+#\ In\ the\ evening
+
+##\ Dinner
+
+\-\ Eat\ spaghetti
+\-\ Drink\ wine
+
+\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-
+
+![picture\ of\ spaghetti](images/spaghetti.jpg)
+
+##\ Going\ to\ sleep
+
+\-\ Get\ in\ bed
+\-\ Count\ sheep
+\f[]
+.fi
+.PP
+To produce an HTML/javascript slide show, simply type
+.IP
+.nf
+\f[C]
+pandoc\ \-t\ FORMAT\ \-s\ habits.txt\ \-o\ habits.html
+\f[]
+.fi
+.PP
+where \f[C]FORMAT\f[] is either \f[C]s5\f[], \f[C]slidy\f[],
+\f[C]slideous\f[], \f[C]dzslides\f[], or \f[C]revealjs\f[].
+.PP
+For Slidy, Slideous, reveal.js, and S5, the file produced by pandoc with
+the \f[C]\-s/\-\-standalone\f[] option embeds a link to javascripts and
+CSS files, which are assumed to be available at the relative path
+\f[C]s5/default\f[] (for S5), \f[C]slideous\f[] (for Slideous),
+\f[C]reveal.js\f[] (for reveal.js), or at the Slidy website at
+\f[C]w3.org\f[] (for Slidy).
+(These paths can be changed by setting the \f[C]slidy\-url\f[],
+\f[C]slideous\-url\f[], \f[C]revealjs\-url\f[], or \f[C]s5\-url\f[]
+variables; see \f[C]\-\-variable\f[], above.) For DZSlides, the
+(relatively short) javascript and css are included in the file by
+default.
+.PP
+With all HTML slide formats, the \f[C]\-\-self\-contained\f[] option can
+be used to produce a single file that contains all of the data necessary
+to display the slide show, including linked scripts, stylesheets,
+images, and videos.
+.PP
+To produce a PDF slide show using beamer, type
+.IP
+.nf
+\f[C]
+pandoc\ \-t\ beamer\ habits.txt\ \-o\ habits.pdf
+\f[]
+.fi
+.PP
+Note that a reveal.js slide show can also be converted to a PDF by
+printing it to a file from the browser.
+.SS Structuring the slide show
+.PP
+By default, the \f[I]slide level\f[] is the highest header level in the
+hierarchy that is followed immediately by content, and not another
+header, somewhere in the document.
+In the example above, level 1 headers are always followed by level 2
+headers, which are followed by content, so 2 is the slide level.
+This default can be overridden using the \f[C]\-\-slide\-level\f[]
+option.
+.PP
+The document is carved up into slides according to the following rules:
+.IP \[bu] 2
+A horizontal rule always starts a new slide.
+.IP \[bu] 2
+A header at the slide level always starts a new slide.
+.IP \[bu] 2
+Headers \f[I]below\f[] the slide level in the hierarchy create headers
+\f[I]within\f[] a slide.
+.IP \[bu] 2
+Headers \f[I]above\f[] the slide level in the hierarchy create "title
+slides," which just contain the section title and help to break the
+slide show into sections.
+.IP \[bu] 2
+A title page is constructed automatically from the document\[aq]s title
+block, if present.
+(In the case of beamer, this can be disabled by commenting out some
+lines in the default template.)
+.PP
+These rules are designed to support many different styles of slide show.
+If you don\[aq]t care about structuring your slides into sections and
+subsections, you can just use level 1 headers for all each slide.
+(In that case, level 1 will be the slide level.) But you can also
+structure the slide show into sections, as in the example above.
+.PP
+Note: in reveal.js slide shows, if slide level is 2, a two\-dimensional
+layout will be produced, with level 1 headers building horizontally and
+level 2 headers building vertically.
+It is not recommended that you use deeper nesting of section levels with
+reveal.js.
+.SS Incremental lists
+.PP
+By default, these writers produce lists that display "all at once." If
+you want your lists to display incrementally (one item at a time), use
+the \f[C]\-i\f[] option.
+If you want a particular list to depart from the default (that is, to
+display incrementally without the \f[C]\-i\f[] option and all at once
+with the \f[C]\-i\f[] option), put it in a block quote:
+.IP
+.nf
+\f[C]
+>\ \-\ Eat\ spaghetti
+>\ \-\ Drink\ wine
+\f[]
+.fi
+.PP
+In this way incremental and nonincremental lists can be mixed in a
+single document.
+.SS Inserting pauses
+.PP
+You can add "pauses" within a slide by including a paragraph containing
+three dots, separated by spaces:
+.IP
+.nf
+\f[C]
+#\ Slide\ with\ a\ pause
+
+content\ before\ the\ pause
+
+\&.\ .\ .
+
+content\ after\ the\ pause
+\f[]
+.fi
+.SS Styling the slides
+.PP
+You can change the style of HTML slides by putting customized CSS files
+in \f[C]$DATADIR/s5/default\f[] (for S5), \f[C]$DATADIR/slidy\f[] (for
+Slidy), or \f[C]$DATADIR/slideous\f[] (for Slideous), where
+\f[C]$DATADIR\f[] is the user data directory (see
+\f[C]\-\-data\-dir\f[], above).
+The originals may be found in pandoc\[aq]s system data directory
+(generally \f[C]$CABALDIR/pandoc\-VERSION/s5/default\f[]).
+Pandoc will look there for any files it does not find in the user data
+directory.
+.PP
+For dzslides, the CSS is included in the HTML file itself, and may be
+modified there.
+.PP
+For reveal.js, themes can be used by setting the \f[C]theme\f[]
+variable, for example:
+.IP
+.nf
+\f[C]
+\-V\ theme=moon
+\f[]
+.fi
+.PP
+Or you can specify a custom stylesheet using the \f[C]\-\-css\f[]
+option.
+.PP
+To style beamer slides, you can specify a beamer "theme" or "colortheme"
+using the \f[C]\-V\f[] option:
+.IP
+.nf
+\f[C]
+pandoc\ \-t\ beamer\ habits.txt\ \-V\ theme:Warsaw\ \-o\ habits.pdf
+\f[]
+.fi
+.PP
+Note that header attributes will turn into slide attributes (on a
+\f[C]<div>\f[] or \f[C]<section>\f[]) in HTML slide formats, allowing
+you to style individual slides.
+In Beamer, the only header attribute that affects slides is the
+\f[C]allowframebreaks\f[] class, which sets the
+\f[C]allowframebreaks\f[] option, causing multiple slides to be created
+if the content overfills the frame.
+This is recommended especially for bibliographies:
+.IP
+.nf
+\f[C]
+#\ References\ {.allowframebreaks}
+\f[]
+.fi
+.SS Speaker notes
+.PP
+reveal.js has good support for speaker notes.
+You can add notes to your markdown document thus:
+.IP
+.nf
+\f[C]
+<div\ class="notes">
+This\ is\ my\ note.
+
+\-\ It\ can\ contain\ markdown
+\-\ like\ this\ list
+
+</div>
+\f[]
+.fi
+.PP
+To show the notes window, press \f[C]s\f[] while viewing the
+presentation.
+Notes are not yet supported for other slide formats, but the notes will
+not appear on the slides themselves.
+.SS Marking frames "fragile" in beamer
+.PP
+Sometimes it is necessary to add the LaTeX \f[C][fragile]\f[] option to
+a frame in beamer (for example, when using the \f[C]minted\f[]
+environment).
+This can be forced by adding the \f[C]fragile\f[] class to the header
+introducing the slide:
+.IP
+.nf
+\f[C]
+#\ Fragile\ slide\ {.fragile}
+\f[]
+.fi
+.SH EPUB METADATA
+.PP
+EPUB metadata may be specified using the \f[C]\-\-epub\-metadata\f[]
+option, but if the source document is markdown, it is better to use a
+YAML metadata block.
+Here is an example:
+.IP
+.nf
+\f[C]
+\-\-\-
+title:
+\-\ type:\ main
+\ \ text:\ My\ Book
+\-\ type:\ subtitle
+\ \ text:\ An\ investigation\ of\ metadata
+creator:
+\-\ role:\ author
+\ \ text:\ John\ Smith
+\-\ role:\ editor
+\ \ text:\ Sarah\ Jones
+identifier:
+\-\ scheme:\ DOI
+\ \ text:\ doi:10.234234.234/33
+publisher:\ \ My\ Press
+rights:\ ©\ 2007\ John\ Smith,\ CC\ BY\-NC
+\&...
+\f[]
+.fi
+.PP
+The following fields are recognized:
+.TP
+.B \f[C]identifier\f[]
+Either a string value or an object with fields \f[C]text\f[] and
+\f[C]scheme\f[].
+Valid values for \f[C]scheme\f[] are \f[C]ISBN\-10\f[],
+\f[C]GTIN\-13\f[], \f[C]UPC\f[], \f[C]ISMN\-10\f[], \f[C]DOI\f[],
+\f[C]LCCN\f[], \f[C]GTIN\-14\f[], \f[C]ISBN\-13\f[],
+\f[C]Legal\ deposit\ number\f[], \f[C]URN\f[], \f[C]OCLC\f[],
+\f[C]ISMN\-13\f[], \f[C]ISBN\-A\f[], \f[C]JP\f[], \f[C]OLCC\f[].
+.RS
+.RE
+.TP
+.B \f[C]title\f[]
+Either a string value, or an object with fields \f[C]file\-as\f[] and
+\f[C]type\f[], or a list of such objects.
+Valid values for \f[C]type\f[] are \f[C]main\f[], \f[C]subtitle\f[],
+\f[C]short\f[], \f[C]collection\f[], \f[C]edition\f[],
+\f[C]extended\f[].
+.RS
+.RE
+.TP
+.B \f[C]creator\f[]
+Either a string value, or an object with fields \f[C]role\f[],
+\f[C]file\-as\f[], and \f[C]text\f[], or a list of such objects.
+Valid values for \f[C]role\f[] are marc relators, but pandoc will
+attempt to translate the human\-readable versions (like "author" and
+"editor") to the appropriate marc relators.
+.RS
+.RE
+.TP
+.B \f[C]contributor\f[]
+Same format as \f[C]creator\f[].
+.RS
+.RE
+.TP
+.B \f[C]date\f[]
+A string value in \f[C]YYYY\-MM\-DD\f[] format.
+(Only the year is necessary.) Pandoc will attempt to convert other
+common date formats.
+.RS
+.RE
+.TP
+.B \f[C]language\f[]
+A string value in RFC5646 format.
+Pandoc will default to the local language if nothing is specified.
+.RS
+.RE
+.TP
+.B \f[C]subject\f[]
+A string value or a list of such values.
+.RS
+.RE
+.TP
+.B \f[C]description\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]type\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]format\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]relation\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]coverage\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]rights\f[]
+A string value.
+.RS
+.RE
+.TP
+.B \f[C]cover\-image\f[]
+A string value (path to cover image).
+.RS
+.RE
+.TP
+.B \f[C]stylesheet\f[]
+A string value (path to CSS stylesheet).
+.RS
+.RE
+.TP
+.B \f[C]page\-progression\-direction\f[]
+Either \f[C]ltr\f[] or \f[C]rtl\f[].
+Specifies the \f[C]page\-progression\-direction\f[] spine attribute.
+.RS
+.RE
+.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]html\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.
+.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.
+.SH SYNTAX HIGHLIGHTING
+.PP
+Pandoc will automatically highlight syntax in fenced code blocks that
+are marked with a language name.
+(See [Extension: \f[C]inline_code_attributes\f[]] and [Extension:
+\f[C]fenced_code_attributes\f[]], above.) The Haskell library
+highlighting\-kate is used for highlighting, which works in HTML, Docx,
+and LaTeX/PDF output.
+The color scheme can be selected using the \f[C]\-\-highlight\-style\f[]
+option.
+The default color scheme is \f[C]pygments\f[], which imitates the
+default color scheme used by the Python library pygments, but pygments
+is not actually used to do the highlighting.
+.PP
+To see a list of language names that pandoc will recognize, type
+\f[C]pandoc\ \-\-version\f[].
+.PP
+To disable highlighting, use the \f[C]\-\-no\-highlight\f[] option.
+.SH CUSTOM WRITERS
+.PP
+Pandoc can be extended with custom writers written in lua.
+(Pandoc includes a lua interpreter, so lua need not be installed
+separately.)
+.PP
+To use a custom writer, simply specify the path to the lua script in
+place of the output format.
+For example:
+.IP
+.nf
+\f[C]
+pandoc\ \-t\ data/sample.lua
+\f[]
+.fi
+.PP
+Creating a custom writer requires writing a lua function for each
+possible element in a pandoc document.
+To get a documented example which you can modify according to your
+needs, do
+.IP
+.nf
+\f[C]
+pandoc\ \-\-print\-default\-data\-file\ sample.lua
+\f[]
+.fi
+.SH AUTHORS
+.PP
+© 2006\-2015 John MacFarlane (jgm\@berkeley.edu).
+Released under the GPL, version 2 or greater.
+This software carries no warranty of any kind.
+(See COPYRIGHT for full copyright and warranty notices.)
+.PP
+Contributors include Aaron Wolen, Albert Krewinkel, Alexander
+Kondratskiy, Alexander Sulfrian, Alexander V Vershilov, Alfred
+Wechselberger, Andreas Lööw, Andrew Dunning, Antoine Latter, Arlo
+O\[aq]Keeffe, Artyom Kazak, Ben Gamari, Beni Cherniavsky\-Paskin, Bjorn
+Buckwalter, Bradley Kuhn, Brent Yorgey, Bryan O\[aq]Sullivan, B.
+Scott Michel, Caleb McDaniel, Calvin Beck, Christoffer Ackelman,
+Christoffer Sawicki, Clare Macrae, Clint Adams, Conal Elliott, Craig S.
+Bosma, Daniel Bergey, Daniel T.
+Staal, David Lazar, David Röthlisberger, Denis Laxalde, Douglas Calvert,
+Douglas F.
+Calvert, Eric Kow, Eric Seidel, Florian Eitel, François Gannaz, Freiric
+Barral, Fyodor Sheremetyev, Gabor Pali, Gavin Beatty, Greg Maslov,
+Grégory Bataille, Greg Rundlett, gwern, Gwern Branwen, Hans\-Peter
+Deifel, Henry de Valence, Ilya V.
+Portnov, infinity0x, Jaime Marquínez Ferrándiz, James Aspnes, Jamie F.
+Olson, Jan Larres, Jason Ronallo, Jeff Arnold, Jeff Runningen, Jens
+Petersen, Jérémy Bobbio, Jesse Rosenthal, J.
+Lewis Muir, Joe Hillenbrand, John MacFarlane, Jonas Smedegaard, Jonathan
+Daugherty, Josef Svenningsson, Jose Luis Duran, Julien Cretel, Justin
+Bogner, Kelsey Hightower, Konstantin Zudov, Lars\-Dominik Braun, Luke
+Plant, Mark Szepieniec, Mark Wright, Masayoshi Takahashi, Matej Kollar,
+Mathias Schenner, Matthew Pickering, Matthias C.
+M.
+Troffaes, Max Bolingbroke, Max Rydahl Andersen, mb21, Merijn
+Verstraaten, Michael Snoyman, Michael Thompson, MinRK, Nathan Gass, Neil
+Mayhew, Nick Bart, Nicolas Kaiser, Nikolay Yakimov, nkalvi, Paulo
+Tanimoto, Paul Rivier, Peter Wang, Philippe Ombredanne, Phillip Alday,
+Puneeth Chaganti, qerub, Ralf Stephan, Recai Oktaş, rodja.trappe,
+RyanGlScott, Scott Morrison, Sergei Trofimovich, Sergey Astanin, Shahbaz
+Youssefi, Shaun Attfield, shreevatsa.public, Simon Hengel, Sumit
+Sahrawat, takahashim, thsutton, Tim Lin, Timothy Humphries, Todd
+Sifleet, Tom Leese, Uli Köhler, Václav Zeman, Viktor Kronvall, Vincent,
+Wikiwide, and Xavier Olive.
+.PP
+The Pandoc source code and all documentation may be downloaded
+from <http://pandoc.org>.
diff --git a/man/pandoc.1.template b/man/pandoc.1.template
new file mode 100644
index 000000000..6a1c26a52
--- /dev/null
+++ b/man/pandoc.1.template
@@ -0,0 +1,10 @@
+$if(has-tables)$
+.\"t
+$endif$
+.TH PANDOC 1 "$date$" "$version$"
+.SH NAME
+pandoc - general markup converter
+$body$
+.PP
+The Pandoc source code and all documentation may be downloaded
+from <http://pandoc.org>.
diff --git a/man/removeLinks.hs b/man/removeLinks.hs
new file mode 100644
index 000000000..d4508e7a3
--- /dev/null
+++ b/man/removeLinks.hs
@@ -0,0 +1,9 @@
+import Text.Pandoc.JSON
+
+main :: IO ()
+main = toJSONFilter removeLinks
+
+removeLinks :: Inline -> [Inline]
+removeLinks (Link l _) = l
+removeLinks x = [x]
+
diff --git a/man/removeNotes.hs b/man/removeNotes.hs
new file mode 100644
index 000000000..e61cb932a
--- /dev/null
+++ b/man/removeNotes.hs
@@ -0,0 +1,9 @@
+import Text.Pandoc.JSON
+
+main :: IO ()
+main = toJSONFilter removeNotes
+
+removeNotes :: Inline -> Inline
+removeNotes (Note _) = Str ""
+removeNotes x = x
+
diff --git a/pandoc.cabal b/pandoc.cabal
index b2f82c04b..d2bbff0c2 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -1,29 +1,31 @@
Name: pandoc
-Version: 1.13.1
+Version: 1.15.0.6
Cabal-Version: >= 1.10
Build-Type: Custom
License: GPL
License-File: COPYING
-Copyright: (c) 2006-2014 John MacFarlane
+Copyright: (c) 2006-2015 John MacFarlane
Author: John MacFarlane <jgm@berkeley.edu>
Maintainer: John MacFarlane <jgm@berkeley.edu>
Bug-Reports: https://github.com/jgm/pandoc/issues
Stability: alpha
-Homepage: http://johnmacfarlane.net/pandoc
+Homepage: http://pandoc.org
Category: Text
Tested-With: GHC == 7.4.2, GHC == 7.6.3, GHC == 7.8.2
Synopsis: Conversion between markup formats
Description: Pandoc is a Haskell library for converting from one markup
format to another, and a command-line tool that uses
this library. It can read markdown and (subsets of) HTML,
- reStructuredText, LaTeX, DocBook, MediaWiki markup, Haddock
- markup, OPML, Emacs Org-Mode, txt2tags and Textile, and it can write
- markdown, reStructuredText, HTML, LaTeX, ConTeXt, Docbook,
- OPML, OpenDocument, ODT, Word docx, RTF, MediaWiki, DokuWiki,
- Textile, groff man pages, plain text, Emacs Org-Mode, AsciiDoc,
- Haddock markup, EPUB (v2 and v3), FictionBook2,
- InDesign ICML, and several kinds of HTML/javascript
- slide shows (S5, Slidy, Slideous, DZSlides, reveal.js).
+ reStructuredText, LaTeX, DocBook, MediaWiki markup, TWiki
+ markup, Haddock markup, OPML, Emacs Org-Mode, txt2tags,
+ Word Docx, ODT, and Textile, and it can write
+ Markdown, reStructuredText, XHTML, HTML 5, LaTeX,
+ ConTeXt, DocBook, OPML, OpenDocument, ODT,
+ Word docx, RTF, MediaWiki, DokuWiki, Textile, groff man
+ pages, plain text, Emacs Org-Mode, AsciiDoc, Haddock markup,
+ EPUB (v2 and v3), FictionBook2, InDesign ICML, and several
+ kinds of HTML/javascript slide shows (S5, Slidy, Slideous,
+ DZSlides, reveal.js).
.
Pandoc extends standard markdown syntax with footnotes,
embedded LaTeX, definition lists, tables, and other
@@ -52,6 +54,7 @@ Data-Files:
data/templates/default.texinfo
data/templates/default.man
data/templates/default.markdown
+ data/templates/default.commonmark
data/templates/default.rst
data/templates/default.plain
data/templates/default.mediawiki
@@ -68,11 +71,32 @@ Data-Files:
data/templates/default.org
data/templates/default.epub
data/templates/default.epub3
- -- data for ODT writer
- data/reference.odt
- -- data for docx writer
- data/reference.docx
- -- stylesheet for EPUB writer
+ -- source files for reference.docx
+ data/docx/[Content_Types].xml
+ data/docx/_rels/.rels
+ data/docx/docProps/app.xml
+ data/docx/docProps/core.xml
+ data/docx/word/document.xml
+ data/docx/word/fontTable.xml
+ data/docx/word/footnotes.xml
+ data/docx/word/numbering.xml
+ data/docx/word/settings.xml
+ data/docx/word/webSettings.xml
+ data/docx/word/styles.xml
+ data/docx/word/_rels/document.xml.rels
+ data/docx/word/_rels/footnotes.xml.rels
+ data/docx/word/theme/theme1.xml
+ -- source files for reference.odt
+ data/odt/mimetype
+ data/odt/manifest.rdf
+ data/odt/styles.xml
+ data/odt/content.xml
+ data/odt/meta.xml
+ data/odt/settings.xml
+ data/odt/Configurations2/accelerator/current.xml
+ data/odt/Thumbnails/thumbnail.png
+ data/odt/META-INF/manifest.xml
+ -- stylesheet for EPUB writer
data/epub.css
-- data for LaTeXMathML writer
data/LaTeXMathML.js
@@ -86,13 +110,12 @@ Data-Files:
Extra-Source-Files:
-- documentation
INSTALL, BUGS, CONTRIBUTING.md, changelog
- -- code to create pandoc.1 man page
- Makefile
- man/man1/pandoc.1.template
- man/man5/pandoc_markdown.5.template
- -- generated man pages (produced post-build)
- man/man1/pandoc.1
- man/man5/pandoc_markdown.5
+ man/pandoc.1
+ -- files needed to build man page
+ man/capitalizeHeaders.hs
+ man/removeNotes.hs
+ man/removeLinks.hs
+ man/pandoc.1.template
-- trypandoc
trypandoc/Makefile
trypandoc/index.html
@@ -106,6 +129,9 @@ Extra-Source-Files:
tests/insert
tests/lalune.jpg
tests/movie.jpg
+ tests/media/rId25.jpg
+ tests/media/rId26.jpg
+ tests/media/rId27.jpg
tests/latex-reader.latex
tests/textile-reader.textile
tests/markdown-reader-more.txt
@@ -169,6 +195,8 @@ Extra-Source-Files:
tests/lhs-test.html+lhs
tests/lhs-test.fragment.html+lhs
tests/pipe-tables.txt
+ tests/dokuwiki_external_images.dokuwiki
+ tests/dokuwiki_external_images.native
tests/dokuwiki_multiblock_table.dokuwiki
tests/dokuwiki_multiblock_table.native
tests/fb2/*.markdown
@@ -182,7 +210,10 @@ Extra-Source-Files:
tests/epub/*.epub
tests/epub/*.native
tests/txt2tags.t2t
-
+ tests/twiki-reader.twiki
+ tests/odt/odt/*.odt
+ tests/odt/markdown/*.md
+ tests/odt/native/*.native
Source-repository head
type: git
location: git://github.com/jgm/pandoc.git
@@ -199,55 +230,60 @@ Flag https
Description: Enable support for downloading of resources over https.
Default: True
-Flag make-pandoc-man-pages
- Description: Build program to regenerate pandoc man pages from README.
- Default: False
-
Flag network-uri
- Description: Get Network.URI from the network-uri package
- Default: True
+ Description: Get Network.URI from the network-uri package
+ Default: True
+
+Flag old-locale
+ Description: Use old-locale and time < 1.5
+ Default: True
Library
Build-Depends: base >= 4.2 && <5,
- syb >= 0.1 && < 0.5,
+ syb >= 0.1 && < 0.6,
containers >= 0.1 && < 0.6,
unordered-containers >= 0.2 && < 0.3,
array >= 0.3 && < 0.6,
parsec >= 3.1 && < 3.2,
mtl >= 1.1 && < 2.3,
- filepath >= 1.1 && < 1.4,
+ filepath >= 1.1 && < 1.5,
process >= 1 && < 1.3,
directory >= 1 && < 1.3,
bytestring >= 0.9 && < 0.11,
text >= 0.11 && < 1.3,
zip-archive >= 0.2.3.4 && < 0.3,
- old-locale >= 1 && < 1.1,
- time >= 1.2 && < 1.5,
HTTP >= 4000.0.5 && < 4000.3,
- texmath >= 0.8 && < 0.9,
+ texmath >= 0.8.1 && < 0.9,
xml >= 1.3.12 && < 1.4,
random >= 1 && < 1.2,
extensible-exceptions >= 0.1 && < 0.2,
pandoc-types >= 1.12.4 && < 1.13,
- aeson >= 0.7 && < 0.9,
+ aeson >= 0.7 && < 0.10,
tagsoup >= 0.13.1 && < 0.14,
base64-bytestring >= 0.1 && < 1.1,
- zlib >= 0.5 && < 0.6,
- highlighting-kate >= 0.5.8.5 && < 0.6,
+ zlib >= 0.5 && < 0.7,
+ highlighting-kate >= 0.6 && < 0.7,
data-default >= 0.4 && < 0.6,
temporary >= 1.1 && < 1.3,
- blaze-html >= 0.5 && < 0.8,
- blaze-markup >= 0.5.1 && < 0.7,
+ blaze-html >= 0.5 && < 0.9,
+ blaze-markup >= 0.5.1 && < 0.8,
yaml >= 0.8.8.2 && < 0.9,
scientific >= 0.2 && < 0.4,
- vector >= 0.10 && < 0.11,
- hslua >= 0.3 && < 0.4,
+ vector >= 0.10 && < 0.12,
+ hslua >= 0.3 && < 0.5,
binary >= 0.5 && < 0.8,
SHA >= 1.6 && < 1.7,
- haddock-library >= 1.1 && < 1.2,
+ haddock-library >= 1.1 && < 1.3,
old-time,
deepseq-generics >= 0.1 && < 0.2,
- JuicyPixels >= 3.1.6.1 && < 3.2
+ JuicyPixels >= 3.1.6.1 && < 3.3,
+ filemanip >= 0.3 && < 0.4,
+ cmark >= 0.4.0.1 && < 0.5
+ if flag(old-locale)
+ Build-Depends: old-locale >= 1 && < 1.1,
+ time >= 1.2 && < 1.5
+ else
+ Build-Depends: time >= 1.5 && < 1.6
if flag(network-uri)
Build-Depends: network-uri >= 2.6 && < 2.7, network >= 2.6
else
@@ -259,12 +295,12 @@ Library
cpp-options: -DHTTP_CLIENT
if flag(embed_data_files)
cpp-options: -DEMBED_DATA_FILES
- -- Build-Tools: hsb2hs -- not yet recognized by cabal
+ Build-Tools: hsb2hs >= 0.3.1
other-modules: Text.Pandoc.Data
if os(windows)
Cpp-options: -D_WINDOWS
Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
- Ghc-Prof-Options: -auto-all -caf-all -rtsopts
+ Ghc-Prof-Options: -fprof-auto-exported -rtsopts
Default-Language: Haskell98
Other-Extensions: PatternGuards, OverloadedStrings,
ScopedTypeVariables, GeneralizedNewtypeDeriving,
@@ -277,9 +313,11 @@ Library
Text.Pandoc.Pretty,
Text.Pandoc.Shared,
Text.Pandoc.MediaBag,
+ Text.Pandoc.Error,
Text.Pandoc.Readers.HTML,
Text.Pandoc.Readers.LaTeX,
Text.Pandoc.Readers.Markdown,
+ Text.Pandoc.Readers.CommonMark,
Text.Pandoc.Readers.MediaWiki,
Text.Pandoc.Readers.RST,
Text.Pandoc.Readers.Org,
@@ -289,7 +327,10 @@ Library
Text.Pandoc.Readers.Textile,
Text.Pandoc.Readers.Native,
Text.Pandoc.Readers.Haddock,
+ Text.Pandoc.Readers.TWiki,
+ Text.Pandoc.Readers.Txt2Tags,
Text.Pandoc.Readers.Docx,
+ Text.Pandoc.Readers.Odt,
Text.Pandoc.Readers.EPUB,
Text.Pandoc.Writers.Native,
Text.Pandoc.Writers.Docbook,
@@ -302,6 +343,7 @@ Library
Text.Pandoc.Writers.Texinfo,
Text.Pandoc.Writers.Man,
Text.Pandoc.Writers.Markdown,
+ Text.Pandoc.Writers.CommonMark,
Text.Pandoc.Writers.Haddock,
Text.Pandoc.Writers.RST,
Text.Pandoc.Writers.Org,
@@ -320,12 +362,24 @@ Library
Text.Pandoc.Templates,
Text.Pandoc.XML,
Text.Pandoc.SelfContained,
- Text.Pandoc.Process,
- Text.Pandoc.Readers.Txt2Tags
+ Text.Pandoc.Process
Other-Modules: Text.Pandoc.Readers.Docx.Lists,
Text.Pandoc.Readers.Docx.Reducible,
Text.Pandoc.Readers.Docx.Parse,
- Text.Pandoc.Readers.Docx.Fonts
+ Text.Pandoc.Readers.Docx.Fonts,
+ Text.Pandoc.Readers.Docx.Util,
+ Text.Pandoc.Readers.Docx.StyleMap,
+ Text.Pandoc.Readers.Odt.Base,
+ Text.Pandoc.Readers.Odt.Namespaces,
+ Text.Pandoc.Readers.Odt.StyleReader,
+ Text.Pandoc.Readers.Odt.ContentReader,
+ Text.Pandoc.Readers.Odt.Generic.Fallible,
+ Text.Pandoc.Readers.Odt.Generic.SetMap,
+ Text.Pandoc.Readers.Odt.Generic.Utils,
+ Text.Pandoc.Readers.Odt.Generic.Namespaces,
+ Text.Pandoc.Readers.Odt.Generic.XMLConverter,
+ Text.Pandoc.Readers.Odt.Arrows.State,
+ Text.Pandoc.Readers.Odt.Arrows.Utils,
Text.Pandoc.Writers.Shared,
Text.Pandoc.Asciify,
Text.Pandoc.MIME,
@@ -334,6 +388,7 @@ Library
Text.Pandoc.ImageSize,
Text.Pandoc.Slides,
Text.Pandoc.Highlighting,
+ Text.Pandoc.Compat.Locale,
Text.Pandoc.Compat.Monoid,
Text.Pandoc.Compat.Except,
Text.Pandoc.Compat.TagSoupEntity,
@@ -347,12 +402,12 @@ Executable pandoc
pandoc-types >= 1.12.4 && < 1.13,
base >= 4.2 && <5,
directory >= 1 && < 1.3,
- filepath >= 1.1 && < 1.4,
+ filepath >= 1.1 && < 1.5,
text >= 0.11 && < 1.3,
bytestring >= 0.9 && < 0.11,
extensible-exceptions >= 0.1 && < 0.2,
- highlighting-kate >= 0.5.8.5 && < 0.6,
- aeson >= 0.7.0.5 && < 0.9,
+ highlighting-kate >= 0.6 && < 0.7,
+ aeson >= 0.7.0.5 && < 0.10,
yaml >= 0.8.8.2 && < 0.9,
containers >= 0.1 && < 0.6,
HTTP >= 4000.0.5 && < 4000.3
@@ -361,7 +416,7 @@ Executable pandoc
else
Build-Depends: network >= 2 && < 2.6
Ghc-Options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind
- Ghc-Prof-Options: -auto-all -caf-all -rtsopts -with-rtsopts=-K16m
+ Ghc-Prof-Options: -fprof-auto-exported -rtsopts -with-rtsopts=-K16m
if os(windows)
Cpp-options: -D_WINDOWS
Default-Language: Haskell98
@@ -384,41 +439,25 @@ Executable trypandoc
else
Buildable: False
--- NOTE: A trick in Setup.hs makes sure this won't be installed:
-Executable make-pandoc-man-pages
- Main-Is: make-pandoc-man-pages.hs
- Hs-Source-Dirs: man
- Build-Depends: pandoc,
- base >= 4.2 && < 5,
- directory >= 1 && < 1.3,
- filepath >= 1.1 && < 1.4,
- old-time >= 1.0 && < 1.2,
- time >= 1.2 && < 1.5
- Default-Language: Haskell98
- if flag(make-pandoc-man-pages)
- Buildable: True
- else
- Buildable: False
-
Test-Suite test-pandoc
Type: exitcode-stdio-1.0
Main-Is: test-pandoc.hs
Hs-Source-Dirs: tests
Build-Depends: base >= 4.2 && < 5,
- syb >= 0.1 && < 0.5,
+ syb >= 0.1 && < 0.6,
pandoc,
pandoc-types >= 1.12.4 && < 1.13,
bytestring >= 0.9 && < 0.11,
text >= 0.11 && < 1.3,
directory >= 1 && < 1.3,
- filepath >= 1.1 && < 1.4,
+ filepath >= 1.1 && < 1.5,
process >= 1 && < 1.3,
- highlighting-kate >= 0.5.8.5 && < 0.6,
+ highlighting-kate >= 0.6 && < 0.7,
Diff >= 0.2 && < 0.4,
test-framework >= 0.3 && < 0.9,
test-framework-hunit >= 0.2 && < 0.4,
test-framework-quickcheck2 >= 0.2.9 && < 0.4,
- QuickCheck >= 2.4 && < 2.8,
+ QuickCheck >= 2.4 && < 2.9,
HUnit >= 1.2 && < 1.3,
containers >= 0.1 && < 0.6,
ansi-terminal >= 0.5 && < 0.7,
@@ -430,10 +469,12 @@ Test-Suite test-pandoc
Tests.Shared
Tests.Walk
Tests.Readers.LaTeX
+ Tests.Readers.HTML
Tests.Readers.Markdown
Tests.Readers.Org
Tests.Readers.RST
Tests.Readers.Docx
+ Tests.Readers.Odt
Tests.Readers.Txt2Tags
Tests.Readers.EPUB
Tests.Writers.Native
@@ -444,7 +485,9 @@ Test-Suite test-pandoc
Tests.Writers.Plain
Tests.Writers.AsciiDoc
Tests.Writers.LaTeX
- Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
+ Tests.Writers.Docx
+ Tests.Writers.RST
+ Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
Default-Language: Haskell98
benchmark benchmark-pandoc
@@ -453,7 +496,7 @@ benchmark benchmark-pandoc
Hs-Source-Dirs: benchmark
Build-Depends: pandoc,
base >= 4.2 && < 5,
- syb >= 0.1 && < 0.5,
- criterion >= 0.5 && < 0.9
+ syb >= 0.1 && < 0.6,
+ criterion >= 0.5 && < 1.1
Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
Default-Language: Haskell98
diff --git a/pandoc.hs b/pandoc.hs
index 71d0c4b98..fb9b9abbf 100644
--- a/pandoc.hs
+++ b/pandoc.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE CPP, TupleSections #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Main
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley@edu>
@@ -49,7 +49,7 @@ import System.Exit ( exitWith, ExitCode (..) )
import System.FilePath
import System.Console.GetOpt
import Data.Char ( toLower )
-import Data.List ( intercalate, isPrefixOf, isSuffixOf, sort )
+import Data.List ( delete, intercalate, isPrefixOf, isSuffixOf, sort )
import System.Directory ( getAppUserDataDirectory, findExecutable,
doesFileExist, Permissions(..), getPermissions )
import System.IO ( stdout, stderr )
@@ -58,7 +58,7 @@ import qualified Control.Exception as E
import Control.Exception.Extensible ( throwIO )
import qualified Text.Pandoc.UTF8 as UTF8
import Control.Monad (when, unless, (>=>))
-import Data.Maybe (isJust, fromMaybe)
+import Data.Maybe (fromMaybe, isNothing)
import Data.Foldable (foldrM)
import Network.URI (parseURI, isURI, URI(..))
import qualified Data.ByteString.Lazy as B
@@ -72,13 +72,15 @@ import Control.Applicative ((<$>), (<|>))
import Text.Pandoc.Readers.Txt2Tags (getT2TMeta)
import Data.Monoid
+import Text.Pandoc.Error
+
type Transform = Pandoc -> Pandoc
copyrightMessage :: String
copyrightMessage = intercalate "\n" [
"",
- "Copyright (C) 2006-2014 John MacFarlane",
- "Web: http://johnmacfarlane.net/pandoc",
+ "Copyright (C) 2006-2015 John MacFarlane",
+ "Web: http://pandoc.org",
"This is free software; see the source for copying conditions.",
"There is no warranty, not even for merchantability or fitness",
"for a particular purpose." ]
@@ -140,12 +142,18 @@ externalFilter f args' d = do
".php" -> ("php", f:args')
_ -> (f, args')
else err 85 $ "Filter " ++ f ++ " not found"
+ when (f' /= f) $ do
+ mbExe <- findExecutable f'
+ when (isNothing mbExe) $
+ err 83 $ "Error running filter " ++ f ++ "\n" ++
+ show f' ++ " not found in path."
(exitcode, outbs, errbs) <- E.handle filterException $
pipeProcess Nothing f' args'' $ encode d
when (not $ B.null errbs) $ B.hPutStr stderr errbs
case exitcode of
ExitSuccess -> return $ either error id $ eitherDecode' outbs
- ExitFailure _ -> err 83 $ "Error running filter " ++ f
+ ExitFailure ec -> err 83 $ "Error running filter " ++ f ++ "\n" ++
+ "Filter returned error status " ++ show ec
where filterException :: E.SomeException -> IO a
filterException e = err 83 $ "Error running filter " ++ f ++ "\n" ++
show e
@@ -186,6 +194,7 @@ data Opt = Opt
, optTOCDepth :: Int -- ^ Number of levels to include in TOC
, optDumpArgs :: Bool -- ^ Output command-line arguments
, optIgnoreArgs :: Bool -- ^ Ignore command-line arguments
+ , optVerbose :: Bool -- ^ Verbose diagnostic output
, optReferenceLinks :: Bool -- ^ Use reference links in writing markdown, rst
, optWrapText :: Bool -- ^ Wrap text
, optColumns :: Int -- ^ Line length in characters
@@ -197,6 +206,7 @@ data Opt = Opt
, optCiteMethod :: CiteMethod -- ^ Method to output cites
, optListings :: Bool -- ^ Use listings package for code blocks
, optLaTeXEngine :: String -- ^ Program to use for latex -> pdf
+ , optLaTeXEngineArgs :: [String] -- ^ Flags to pass to the latex-engine
, optSlideLevel :: Maybe Int -- ^ Header level that creates slides
, optSetextHeaders :: Bool -- ^ Use atx headers for markdown level 1-2
, optAscii :: Bool -- ^ Use ascii characters only in html
@@ -246,6 +256,7 @@ defaultOpts = Opt
, optTOCDepth = 3
, optDumpArgs = False
, optIgnoreArgs = False
+ , optVerbose = False
, optReferenceLinks = False
, optWrapText = True
, optColumns = 72
@@ -257,6 +268,7 @@ defaultOpts = Opt
, optCiteMethod = Citeproc
, optListings = False
, optLaTeXEngine = "pdflatex"
+ , optLaTeXEngineArgs = []
, optSlideLevel = Nothing
, optSetextHeaders = True
, optAscii = False
@@ -732,14 +744,19 @@ options =
"PROGRAM")
"" -- "Name of latex program to use in generating PDF"
+ , Option "" ["latex-engine-opt"]
+ (ReqArg
+ (\arg opt -> do
+ let oldArgs = optLaTeXEngineArgs opt
+ return opt { optLaTeXEngineArgs = arg : oldArgs })
+ "STRING")
+ "" -- "Flags to pass to the LaTeX engine, all instances of this option are accumulated and used"
+
, Option "" ["bibliography"]
(ReqArg
(\arg opt -> return opt{ optMetadata = addMetadata
"bibliography" (readMetaValue arg)
$ optMetadata opt
- , optVariables =
- ("biblio-files", dropExtension arg) :
- optVariables opt
})
"FILE")
""
@@ -818,7 +835,7 @@ options =
(\arg opt -> do
let url' = case arg of
Just u -> u
- Nothing -> "//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
+ Nothing -> "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"
return opt { optHTMLMathMethod = MathJax url'})
"URL")
"" -- "Use MathJax for HTML math"
@@ -827,7 +844,7 @@ options =
(\arg opt ->
return opt
{ optKaTeXJS =
- arg <|> Just "http://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.js"})
+ arg <|> Just "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.js"})
"URL")
"" -- Use KaTeX for HTML Math
@@ -858,6 +875,11 @@ options =
(\opt -> return opt { optIgnoreArgs = True }))
"" -- "Ignore command-line arguments."
+ , Option "" ["verbose"]
+ (NoArg
+ (\opt -> return opt { optVerbose = True }))
+ "" -- "Verbose diagnostic output."
+
, Option "v" ["version"]
(NoArg
(\_ -> do
@@ -898,13 +920,15 @@ readMetaValue s = case decode (UTF8.fromString s) of
usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
usageMessage programName = usageInfo
(programName ++ " [OPTIONS] [FILES]" ++ "\nInput formats: " ++
- (wrapWords 16 78 $ readers'names) ++ "\nOutput formats: " ++
+ (wrapWords 16 78 $ readers'names) ++
+ '\n' : replicate 16 ' ' ++
+ "[ *only Pandoc's JSON version of native AST]" ++ "\nOutput formats: " ++
(wrapWords 16 78 $ writers'names) ++
'\n' : replicate 16 ' ' ++
- "[*for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
+ "[**for pdf output, use latex or beamer and -o FILENAME.pdf]\nOptions:")
where
- writers'names = sort $ "pdf*" : map fst writers
- readers'names = sort $ map fst readers
+ writers'names = sort $ "json*" : "pdf**" : delete "json" (map fst writers)
+ readers'names = sort $ "json*" : delete "json" (map fst readers)
-- Determine default reader based on source file extensions
defaultReaderName :: String -> [FilePath] -> String
@@ -930,6 +954,9 @@ defaultReaderName fallback (x:xs) =
".docx" -> "docx"
".t2t" -> "t2t"
".epub" -> "epub"
+ ".odt" -> "odt"
+ ".pdf" -> "pdf" -- so we get an "unknown reader" error
+ ".doc" -> "doc" -- so we get an "unknown reader" error
_ -> defaultReaderName fallback xs
-- Returns True if extension of first source is .lhs
@@ -970,6 +997,7 @@ defaultWriterName x =
".pdf" -> "latex"
".fb2" -> "fb2"
".opml" -> "opml"
+ ".icml" -> "icml"
['.',y] | y `elem` ['1'..'9'] -> "man"
_ -> "html"
@@ -1057,6 +1085,7 @@ main = do
, optTOCDepth = epubTOCDepth
, optDumpArgs = dumpArgs
, optIgnoreArgs = ignoreArgs
+ , optVerbose = verbose
, optReferenceLinks = referenceLinks
, optWrapText = wrap
, optColumns = columns
@@ -1068,6 +1097,7 @@ main = do
, optCiteMethod = citeMethod
, optListings = listings
, optLaTeXEngine = latexEngine
+ , optLaTeXEngineArgs = latexEngineArgs
, optSlideLevel = slideLevel
, optSetextHeaders = setextHeaders
, optAscii = ascii
@@ -1085,7 +1115,7 @@ main = do
mapM_ (\arg -> UTF8.hPutStrLn stdout arg) args
exitWith ExitSuccess
- let csscdn = "http://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.css"
+ let csscdn = "https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.1.0/katex.min.css"
let mathMethod =
case (katexJS, katexStylesheet) of
(Nothing, _) -> mathMethod'
@@ -1093,7 +1123,7 @@ main = do
-- --bibliography implies -F pandoc-citeproc for backwards compatibility:
- let needsCiteproc = isJust (M.lookup "bibliography" metadata) &&
+ let needsCiteproc = any ("--bibliography" `isPrefixOf`) rawArgs &&
optCiteMethod opts `notElem` [Natbib, Biblatex] &&
"pandoc-citeproc" `notElem` map takeBaseName filters
let filters' = if needsCiteproc then "pandoc-citeproc" : filters
@@ -1148,7 +1178,13 @@ main = do
(getT2TMeta sources outputFile)
else case getReader readerName' of
Right r -> return r
- Left e -> err 7 e
+ Left e -> err 7 e'
+ where e' = case readerName' of
+ "pdf" -> e ++
+ "\nPandoc can convert to PDF, but not from PDF."
+ "doc" -> e ++
+ "\nPandoc can convert from DOCX, but not from DOC.\nTry using Word to save your DOC file as DOCX, and convert that with pandoc."
+ _ -> e
let standalone' = standalone || not (isTextFormat writerName') || pdfOutput
@@ -1235,23 +1271,24 @@ main = do
Right (bs,_) -> return $ UTF8.toString bs
let readFiles [] = error "Cannot read archive from stdin"
- readFiles (x:_) = B.readFile x
+ readFiles [x] = B.readFile x
+ readFiles (x:xs) = mapM (warn . ("Ignoring: " ++)) xs >> B.readFile x
let convertTabs = tabFilter (if preserveTabs || readerName' == "t2t"
then 0
else tabStop)
- let handleIncludes' = if readerName' == "latex" ||
- readerName' == "latex+lhs"
+ let handleIncludes' :: String -> IO (Either PandocError String)
+ handleIncludes' = if readerName' `elem` ["latex", "latex+lhs"]
then handleIncludes
- else return
-
- (doc, media) <-
- case reader of
- StringReader r-> (, mempty) <$>
- ( readSources >=>
- handleIncludes' . convertTabs . intercalate "\n" >=>
- r readerOpts ) sources
+ else return . Right
+
+ (doc, media) <- fmap handleError $
+ case reader of
+ StringReader r-> do
+ srcs <- convertTabs . intercalate "\n" <$> readSources sources
+ doc <- handleIncludes' srcs
+ either (return . Left) (\s -> fmap (,mempty) <$> r readerOpts s) doc
ByteStringReader r -> readFiles sources >>= r readerOpts
let writerOptions = def { writerStandalone = standalone',
@@ -1290,7 +1327,9 @@ main = do
writerTOCDepth = epubTOCDepth,
writerReferenceODT = referenceODT,
writerReferenceDocx = referenceDocx,
- writerMediaBag = media
+ writerMediaBag = media,
+ writerVerbose = verbose,
+ writerLaTeXArgs = latexEngineArgs
}
diff --git a/relann1.6 b/relann1.6
deleted file mode 100644
index 131625d5c..000000000
--- a/relann1.6
+++ /dev/null
@@ -1,170 +0,0 @@
-I'm pleased to announce the release of pandoc 1.6.
-
-As usual, a source tarball and Windows installer are available
-at <http://code.google.com/p/pandoc/downloads/list>. You can
-also use 'cabal install' to get the latest version from HackageDB:
-
- cabal update
- cabal install pandoc
-
-Thanks to everyone who contributed, either by filing bug reports or by
-contributing patches. Here is a summary of the major changes in this
-version:
-
-+ New EPUB and HTML Slidy writers. (Issue #122)
-
- - [EPUB] is a standard ebook format, used in Apple's iBooks for
- the iPad and iPhone, Barnes and Noble's nook reader, the Sony
- reader, and many other devices, and by online ebook readers like
- [bookworm]. (Amazon's Kindle uses a different format, MobiPocket,
- but EPUB books can easily be converted to Kindle format.) Now you
- can write your book in markdown and produce an ebook with a single
- command! I've put up a short [tutorial here].
- - [Slidy], like S5, is a system for producing HTML+javascript slide shows.
-
-+ All input is assumed to be UTF-8, no matter what the locale and ghc
- version, and all output is UTF-8. This reverts to pre-1.5 behavior.
- Also, a BOM, if present, is stripped from the input.
-
-+ Markdown now supports grid tables, whose cells can contain
- arbitrary block elements. (Issue #43)
-
-+ Sequentially numbered example lists in markdown with `@` marker.
-
-+ Markdown table captions can begin with a bare colon and no longer need
- to include the English word "table." Also, a caption can now occur
- either before or after the table. (Issue #227)
-
-+ New command-line options:
-
- - `--epub-stylesheet` allows you to specify a CSS file that will
- be used to style your ebook.
- - `--epub-metadata` allows you to specify metadata for the ebook.
- - `--offline` causes the generated HTML slideshow to include all
- needed scripts and stylesheets.
- - `--webtex` causes TeX math to be converted to images using the
- Google Charts API (unless a different URL is specified).
- - `--section-divs` causes div tags to be added around each section
- in an HTML document. (Issue #230, 239)
-
-+ Default behavior of S5 writer in standalone mode has changed:
- previously, it would include all needed scripts and stylesheets
- in the generated HTML; now, only links are included unless
- the `--offline` option is used.
-
-+ Default behavior of HTML writer has changed. Between 1.2 and 1.5,
- pandoc would enclose sections in div tags with identifiers on the
- div tags, so that the sections can be manipulated in javascript.
- This caused undesirable interactions with raw HTML div tags. So,
- starting with 1.6, the default is to put the identifiers directly
- on the header tags, and not to include the divs. The `--section-divs`
- option selects the 1.2-1.5 behavior.
-
-+ API changes:
-
- - `HTMLMathMethod`: Added `WebTeX`, removed `MimeTeX`.
- - `WriterOptions`: Added `writerUserDataDir`, `writerSourceDirectory`,
- `writerEPUBMetadata` fields. Removed `writerIncludeBefore`,
- `writerIncludeAfter`.
- - Added `headerShift` to `Text.Pandoc.Shared`.
- - Moved parsing code and `ParserState` from `Text.Pandoc.Shared`
- to a new module, `Text.Pandoc.Parsing`.
- - Added `stateHasChapters` to `ParserState`.
- - Added `HTMLSlideVariant`.
- - Made `KeyTable` a map instead of an association list.
- - Added accessors for `Meta` fields (`docTitle`, `docAuthors`, `docDate`).
- - `Pandoc`, `Meta`, `Inline`, and `Block` have been given `Ord` instances.
- - Reference keys now have a type of their own (`Key`), with its
- own `Ord` instance for case-insensitive comparison.
- - Added `Text.Pandoc.Writers.EPUB`.
- - Added `Text.Pandoc.UUID`.
- - Removed `Text.Pandoc.ODT`, added `Text.Pandoc.Writers.ODT`.
- Removed `saveOpenDocumentAsODT`, added `writeODT`.
- - Added `Text.Pandoc.Writers.Native` and `writeNative`.
- Removed `prettyPandoc`.
- - Added `Text.Pandoc.UTF8` for portable UTF8 string IO.
- - Removed `Text.Pandoc.Writers.S5` and the `writeS5` function.
- Moved `s5Includes` to a new module, `Text.Pandoc.S5`.
- To write S5, you now use `writeHtml` with `writerSlideVariant`
- set to `S5Slides` or `SlidySlides`.
-
-+ Template changes. If you use custom templates, please update them,
- particularly if you use syntax highlighting with pandoc. The old HTML
- templates hardcoded highlighting CSS that will no longer work with
- the most recent version of highlighting-kate.
-
- - HTML template: avoid empty meta tag if no date.
- - HTML template: Use default highlighting CSS from highlighting-kate
- instead of hard-coding the CSS into the template.
- - HTML template: insert-before text goes before the title, and
- immediately after the <body> tag, as documented. (Issue #241)
- - Added slidy and s5 templates.
- - Added amssymb to preamble of latex template. (github Issue 1)
-
-+ Removed excess newlines at the end of output. Note: because output
- will not contain an extra newline, you may need to make adjustments
- if you are inserting pandoc's output into a template.
-
-+ In S5 and slidy, horizontal rules now cause a new slide, so you
- are no longer limited to one slide per section.
-
-+ Improved handling of code in man writer. Inline code is now monospace,
- not bold, and code blocks now use .nf (no fill) and .IP (indented para).
-
-+ HTML reader parses `<tt>` as Code. (Issue #247)
-
-+ html+lhs output now contains bird tracks, even when compiled without
- highlighting support. (Issue #242)
-
-+ Colons are now no longer allowed in autogenerated XML/HTML identifiers,
- since they have a special meaning in XML.
-
-+ Code improvements in ODT writer. Remote images are now replaced with
- their alt text rather than a broken link.
-
-+ LaTeX reader improvements:
-
- - Made latex `\section`, `\chapter` parsers more forgiving of whitespace.
- - Parse `\chapter{}` in latex.
- - Changed `rawLaTeXInline` to accept `\section`, `\begin`, etc.
- - Use new `rawLaTeXInline'` in LaTeX reader, and export `rawLaTeXInline`
- for use in markdown reader.
- - Fixes bug wherein `\section{foo}` was not recognized as raw TeX
- in markdown document.
-
-+ LaTeX writer: images are automatically shrunk if they would extend
- beyond the page margin.
-
-+ Plain, markdown, RST writers now use unicode for smart punctuation.
-
-+ Man writer converts math to unicode when possible, as in other writers.
-
-+ `markdown2pdf` can now recognize citeproc options.
-
-+ Command-line arguments are converted to UTF-8. (Issue #234)
-
-+ `Text.Pandoc.TeXMath` has been rewritten to use texmath's parser.
- This allows it to handle a wider range of formulas. Also, if a formula
- cannot be converted, it is left in raw TeX; formulas are no longer
- partially converted.
-
-+ Unicode curly quotes are left alone when parsing smart quotes. (Issue #143)
-
-+ Cabal file changes:
-
- - Removed parsec < 3 restriction.
- - Added 'threaded' flag for architectures where GHC lacks a threaded
- runtime.
- - Use 'threaded' only for markdown2pdf; it is not needed for pandoc.
- - Require highlighting-kate 0.2.7.
-
-+ Use explicit imports from `Data.Generics`. Otherwise we have a
- conflict with the 'empty' symbol, introduced in syb >= 0.2. (Issue #237)
-
-+ New data files: slidy/slidy.min.js, slidy/slidy.min.css, epub.css.
-
-[EPUB]: http://en.wikipedia.org/wiki/EPUB
-[Slidy]: http://www.w3.org/Talks/Tools/Slidy
-[bookworm]: http://bookworm.oreilly.com/
-[tutorial here]: http://johnmacfarlane.net/pandoc/epub.html
-
diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs
index fd849316b..a4d963221 100644
--- a/src/Text/Pandoc.hs
+++ b/src/Text/Pandoc.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables, FlexibleInstances #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -37,10 +37,12 @@ inline links:
> module Main where
> import Text.Pandoc
+> import Text.Pandoc.Error (handleError)
>
> markdownToRST :: String -> String
-> markdownToRST =
-> (writeRST def {writerReferenceLinks = True}) . readMarkdown def
+> markdownToRST = handleError .
+> writeRST def {writerReferenceLinks = True} .
+> readMarkdown def
>
> main = getContents >>= putStrLn . markdownToRST
@@ -65,7 +67,9 @@ module Text.Pandoc
, Reader (..)
, mkStringReader
, readDocx
+ , readOdt
, readMarkdown
+ , readCommonMark
, readMediaWiki
, readRST
, readOrg
@@ -77,11 +81,12 @@ module Text.Pandoc
, readHaddock
, readNative
, readJSON
+ , readTWiki
, readTxt2Tags
, readTxt2TagsNoMacros
, readEPUB
-- * Writers: converting /from/ Pandoc format
- , Writer (..)
+ , Writer (..)
, writeNative
, writeJSON
, writeMarkdown
@@ -108,6 +113,7 @@ module Text.Pandoc
, writeOrg
, writeAsciiDoc
, writeHaddock
+ , writeCommonMark
, writeCustom
-- * Rendering templates and default templates
, module Text.Pandoc.Templates
@@ -123,6 +129,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Generic
import Text.Pandoc.JSON
import Text.Pandoc.Readers.Markdown
+import Text.Pandoc.Readers.CommonMark
import Text.Pandoc.Readers.MediaWiki
import Text.Pandoc.Readers.RST
import Text.Pandoc.Readers.Org
@@ -133,7 +140,9 @@ import Text.Pandoc.Readers.HTML
import Text.Pandoc.Readers.Textile
import Text.Pandoc.Readers.Native
import Text.Pandoc.Readers.Haddock
+import Text.Pandoc.Readers.TWiki
import Text.Pandoc.Readers.Docx
+import Text.Pandoc.Readers.Odt
import Text.Pandoc.Readers.Txt2Tags
import Text.Pandoc.Readers.EPUB
import Text.Pandoc.Writers.Native
@@ -159,11 +168,13 @@ import Text.Pandoc.Writers.Textile
import Text.Pandoc.Writers.Org
import Text.Pandoc.Writers.AsciiDoc
import Text.Pandoc.Writers.Haddock
+import Text.Pandoc.Writers.CommonMark
import Text.Pandoc.Writers.Custom
import Text.Pandoc.Templates
import Text.Pandoc.Options
-import Text.Pandoc.Shared (safeRead, warn)
+import Text.Pandoc.Shared (safeRead, warn, mapLeft)
import Text.Pandoc.MediaBag (MediaBag)
+import Text.Pandoc.Error
import Data.Aeson
import qualified Data.ByteString.Lazy as BL
import Data.List (intercalate)
@@ -199,32 +210,35 @@ parseFormatSpec = parse formatSpec ""
'-' -> Set.delete ext
_ -> Set.insert ext
--- auxiliary function for readers:
-markdown :: ReaderOptions -> String -> IO Pandoc
-markdown o s = do
- let (doc, warnings) = readMarkdownWithWarnings o s
- mapM_ warn warnings
- return doc
-data Reader = StringReader (ReaderOptions -> String -> IO Pandoc)
- | ByteStringReader (ReaderOptions -> BL.ByteString -> IO (Pandoc, MediaBag))
+data Reader = StringReader (ReaderOptions -> String -> IO (Either PandocError Pandoc))
+ | ByteStringReader (ReaderOptions -> BL.ByteString -> IO (Either PandocError (Pandoc,MediaBag)))
-mkStringReader :: (ReaderOptions -> String -> Pandoc) -> Reader
+mkStringReader :: (ReaderOptions -> String -> (Either PandocError Pandoc)) -> Reader
mkStringReader r = StringReader (\o s -> return $ r o s)
-mkBSReader :: (ReaderOptions -> BL.ByteString -> (Pandoc, MediaBag)) -> Reader
+mkStringReaderWithWarnings :: (ReaderOptions -> String -> Either PandocError (Pandoc, [String])) -> Reader
+mkStringReaderWithWarnings r = StringReader $ \o s -> do
+ case r o s of
+ Left err -> return $ Left err
+ Right (doc, warnings) -> do
+ mapM_ warn warnings
+ return (Right doc)
+
+mkBSReader :: (ReaderOptions -> BL.ByteString -> (Either PandocError (Pandoc, MediaBag))) -> Reader
mkBSReader r = ByteStringReader (\o s -> return $ r o s)
-- | Association list of formats and readers.
readers :: [(String, Reader)]
readers = [ ("native" , StringReader $ \_ s -> return $ readNative s)
,("json" , mkStringReader readJSON )
- ,("markdown" , StringReader markdown)
- ,("markdown_strict" , StringReader markdown)
- ,("markdown_phpextra" , StringReader markdown)
- ,("markdown_github" , StringReader markdown)
- ,("markdown_mmd", StringReader markdown)
- ,("rst" , mkStringReader readRST )
+ ,("markdown" , mkStringReaderWithWarnings readMarkdownWithWarnings)
+ ,("markdown_strict" , mkStringReaderWithWarnings readMarkdownWithWarnings)
+ ,("markdown_phpextra" , mkStringReaderWithWarnings readMarkdownWithWarnings)
+ ,("markdown_github" , mkStringReaderWithWarnings readMarkdownWithWarnings)
+ ,("markdown_mmd", mkStringReaderWithWarnings readMarkdownWithWarnings)
+ ,("commonmark" , mkStringReader readCommonMark)
+ ,("rst" , mkStringReaderWithWarnings readRSTWithWarnings )
,("mediawiki" , mkStringReader readMediaWiki)
,("docbook" , mkStringReader readDocBook)
,("opml" , mkStringReader readOPML)
@@ -233,7 +247,9 @@ readers = [ ("native" , StringReader $ \_ s -> return $ readNative s)
,("html" , mkStringReader readHtml)
,("latex" , mkStringReader readLaTeX)
,("haddock" , mkStringReader readHaddock)
+ ,("twiki" , mkStringReader readTWiki)
,("docx" , mkBSReader readDocx)
+ ,("odt" , mkBSReader readOdt)
,("t2t" , mkStringReader readTxt2TagsNoMacros)
,("epub" , mkBSReader readEPUB)
]
@@ -294,6 +310,7 @@ writers = [
,("org" , PureStringWriter writeOrg)
,("asciidoc" , PureStringWriter writeAsciiDoc)
,("haddock" , PureStringWriter writeHaddock)
+ ,("commonmark" , PureStringWriter writeCommonMark)
]
getDefaultExtensions :: String -> Set Extension
@@ -302,7 +319,7 @@ getDefaultExtensions "markdown_phpextra" = phpMarkdownExtraExtensions
getDefaultExtensions "markdown_mmd" = multimarkdownExtensions
getDefaultExtensions "markdown_github" = githubMarkdownExtensions
getDefaultExtensions "markdown" = pandocExtensions
-getDefaultExtensions "plain" = pandocExtensions
+getDefaultExtensions "plain" = plainExtensions
getDefaultExtensions "org" = Set.fromList [Ext_citations]
getDefaultExtensions "textile" = Set.fromList [Ext_auto_identifiers]
getDefaultExtensions "html" = Set.fromList [Ext_auto_identifiers,
@@ -355,8 +372,8 @@ class ToJSONFilter a => ToJsonFilter a
where toJsonFilter :: a -> IO ()
toJsonFilter = toJSONFilter
-readJSON :: ReaderOptions -> String -> Pandoc
-readJSON _ = either error id . eitherDecode' . UTF8.fromStringLazy
+readJSON :: ReaderOptions -> String -> Either PandocError Pandoc
+readJSON _ = mapLeft ParseFailure . eitherDecode' . UTF8.fromStringLazy
writeJSON :: WriterOptions -> Pandoc -> String
writeJSON _ = UTF8.toStringLazy . encode
diff --git a/src/Text/Pandoc/Asciify.hs b/src/Text/Pandoc/Asciify.hs
index 66490d5c6..c183458e4 100644
--- a/src/Text/Pandoc/Asciify.hs
+++ b/src/Text/Pandoc/Asciify.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Asciify
- Copyright : Copyright (C) 2013-2014 John MacFarlane
+ Copyright : Copyright (C) 2013-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Compat/Locale.hs b/src/Text/Pandoc/Compat/Locale.hs
new file mode 100644
index 000000000..ac791136c
--- /dev/null
+++ b/src/Text/Pandoc/Compat/Locale.hs
@@ -0,0 +1,9 @@
+{-# LANGUAGE CPP #-}
+module Text.Pandoc.Compat.Locale ( defaultTimeLocale )
+where
+
+#if MIN_VERSION_time(1,5,0)
+import Data.Time.Format ( defaultTimeLocale )
+#else
+import System.Locale ( defaultTimeLocale )
+#endif
diff --git a/src/Text/Pandoc/Data.hsb b/src/Text/Pandoc/Data.hsb
index 28e7f5112..3a0bf8ac4 100644
--- a/src/Text/Pandoc/Data.hsb
+++ b/src/Text/Pandoc/Data.hsb
@@ -4,4 +4,4 @@ module Text.Pandoc.Data (dataFiles) where
import qualified Data.ByteString as B
dataFiles :: [(FilePath, B.ByteString)]
-dataFiles = %blobs "data"
+dataFiles = ("README", %blob "README") : %blobs "data" \ No newline at end of file
diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs
new file mode 100644
index 000000000..73d1e8f08
--- /dev/null
+++ b/src/Text/Pandoc/Error.hs
@@ -0,0 +1,64 @@
+{-
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+{- |
+ Module : Text.Pandoc.Error
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+This module provides a standard way to deal with possible errors encounted
+during parsing.
+
+-}
+module Text.Pandoc.Error (PandocError(..), handleError) where
+
+import Text.Parsec.Error
+import Text.Parsec.Pos hiding (Line)
+import Text.Pandoc.Compat.Except
+
+type Input = String
+
+data PandocError = -- | Generic parse failure
+ ParseFailure String
+ -- | Error thrown by a Parsec parser
+ | ParsecError Input ParseError
+ deriving (Show)
+
+
+instance Error PandocError where
+ strMsg = ParseFailure
+
+
+-- | An unsafe method to handle `PandocError`s.
+handleError :: Either PandocError a -> a
+handleError (Right r) = r
+handleError (Left err) =
+ case err of
+ ParseFailure string -> error string
+ ParsecError input err' ->
+ let errPos = errorPos err'
+ errLine = sourceLine errPos
+ errColumn = sourceColumn errPos
+ theline = (lines input ++ [""]) !! (errLine - 1)
+ in error $ "\nError at " ++ show err' ++ "\n" ++
+ theline ++ "\n" ++ replicate (errColumn - 1) ' ' ++
+ "^"
+
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
index 7f975d4c6..d0b945d45 100644
--- a/src/Text/Pandoc/Highlighting.hs
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Highlighting
- Copyright : Copyright (C) 2008-2014 John MacFarlane
+ Copyright : Copyright (C) 2008-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs
index 68b34dcf3..09c1dd443 100644
--- a/src/Text/Pandoc/ImageSize.hs
+++ b/src/Text/Pandoc/ImageSize.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
+{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-
- Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@
{- |
Module : Text.Pandoc.ImageSize
-Copyright : Copyright (C) 2011-2014 John MacFarlane
+Copyright : Copyright (C) 2011-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -38,8 +39,11 @@ import Control.Monad
import Data.Bits
import Data.Binary
import Data.Binary.Get
-import Text.Pandoc.Shared (safeRead)
+import Text.Pandoc.Shared (safeRead, hush)
import qualified Data.Map as M
+import Text.Pandoc.Compat.Except
+import Control.Monad.Trans
+import Data.Maybe (fromMaybe)
-- quick and dirty functions to get image sizes
-- algorithms borrowed from wwwis.pl
@@ -64,17 +68,19 @@ imageType img = case B.take 4 img of
"%!PS"
| (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
-> return Eps
- _ -> fail "Unknown image type"
+ _ -> mzero
-imageSize :: ByteString -> Maybe ImageSize
-imageSize img = do
- t <- imageType img
- case t of
- Png -> pngSize img
- Gif -> gifSize img
- Jpeg -> jpegSize img
- Eps -> epsSize img
- Pdf -> Nothing -- TODO
+imageSize :: ByteString -> Either String ImageSize
+imageSize img =
+ case imageType img of
+ Just Png -> mbToEither "could not determine PNG size" $ pngSize img
+ Just Gif -> mbToEither "could not determine GIF size" $ gifSize img
+ Just Jpeg -> jpegSize img
+ Just Eps -> mbToEither "could not determine EPS size" $ epsSize img
+ Just Pdf -> Left "could not determine PDF size" -- TODO
+ Nothing -> Left "could not determine image type"
+ where mbToEither msg Nothing = Left msg
+ mbToEither _ (Just x) = Right x
defaultSize :: (Integer, Integer)
defaultSize = (72, 72)
@@ -114,7 +120,7 @@ pngSize img = do
([w1,w2,w3,w4,h1,h2,h3,h4] :: [Integer]) -> return
((shift w1 24) + (shift w2 16) + (shift w3 8) + w4,
(shift h1 24) + (shift h2 16) + (shift h3 8) + h4)
- _ -> fail "PNG parse error"
+ _ -> (hush . Left) "PNG parse error"
let (dpix, dpiy) = findpHYs rest''
return $ ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy }
@@ -143,67 +149,84 @@ gifSize img = do
dpiX = 72,
dpiY = 72
}
- _ -> fail "GIF parse error"
+ _ -> (hush . Left) "GIF parse error"
-jpegSize :: ByteString -> Maybe ImageSize
-jpegSize img = do
+jpegSize :: ByteString -> Either String ImageSize
+jpegSize img =
let (hdr, rest) = B.splitAt 4 img
- guard $ B.length rest >= 14
- case hdr of
- "\xff\xd8\xff\xe0" -> jfifSize rest
- "\xff\xd8\xff\xe1" -> exifSize $ B.takeWhile (/= '\xff') rest
- _ -> mzero
+ in if B.length rest < 14
+ then Left "unable to determine JPEG size"
+ else case hdr of
+ "\xff\xd8\xff\xe0" -> jfifSize rest
+ "\xff\xd8\xff\xe1" -> exifSize rest
+ _ -> Left "unable to determine JPEG size"
-jfifSize :: ByteString -> Maybe ImageSize
-jfifSize rest = do
+jfifSize :: ByteString -> Either String ImageSize
+jfifSize rest =
let [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] = map fromIntegral
$ unpack $ B.take 5 $ B.drop 9 $ rest
- let factor = case dpiDensity of
+ factor = case dpiDensity of
1 -> id
2 -> \x -> (x * 254 `div` 10)
_ -> const 72
- let dpix = factor (shift dpix1 8 + dpix2)
- let dpiy = factor (shift dpiy1 8 + dpiy2)
- (w,h) <- findJfifSize rest
- return $ ImageSize { pxX = w, pxY = h, dpiX = dpix, dpiY = dpiy }
+ dpix = factor (shift dpix1 8 + dpix2)
+ dpiy = factor (shift dpiy1 8 + dpiy2)
+ in case findJfifSize rest of
+ Left msg -> Left msg
+ Right (w,h) -> Right $ ImageSize { pxX = w
+ , pxY = h
+ , dpiX = dpix
+ , dpiY = dpiy }
-findJfifSize :: ByteString -> Maybe (Integer,Integer)
-findJfifSize bs = do
+findJfifSize :: ByteString -> Either String (Integer,Integer)
+findJfifSize bs =
let bs' = B.dropWhile (=='\xff') $ B.dropWhile (/='\xff') bs
- case B.uncons bs' of
- Just (c,bs'') | c >= '\xc0' && c <= '\xc3' -> do
+ in case B.uncons bs' of
+ Just (c,bs'') | c >= '\xc0' && c <= '\xc3' ->
case map fromIntegral $ unpack $ B.take 4 $ B.drop 3 bs'' of
- [h1,h2,w1,w2] -> return (shift w1 8 + w2, shift h1 8 + h2)
- _ -> fail "JPEG parse error"
- Just (_,bs'') -> do
+ [h1,h2,w1,w2] -> Right (shift w1 8 + w2, shift h1 8 + h2)
+ _ -> Left "JFIF parse error"
+ Just (_,bs'') ->
case map fromIntegral $ unpack $ B.take 2 bs'' of
- [c1,c2] -> do
+ [c1,c2] ->
let len = shift c1 8 + c2
-- skip variables
- findJfifSize $ B.drop len bs''
- _ -> fail "JPEG parse error"
- Nothing -> fail "Did not find length record"
+ in findJfifSize $ B.drop len bs''
+ _ -> Left "JFIF parse error"
+ Nothing -> Left "Did not find JFIF length record"
-exifSize :: ByteString -> Maybe ImageSize
-exifSize bs = runGet (Just <$> exifHeader bl) bl
+runGet' :: Get (Either String a) -> BL.ByteString -> Either String a
+runGet' p bl =
+#if MIN_VERSION_binary(0,7,0)
+ case runGetOrFail p bl of
+ Left (_,_,msg) -> Left msg
+ Right (_,_,x) -> x
+#else
+ runGet p bl
+#endif
+
+
+exifSize :: ByteString -> Either String ImageSize
+exifSize bs = runGet' header $ bl
where bl = BL.fromChunks [bs]
+ header = runExceptT $ exifHeader bl
-- NOTE: It would be nicer to do
-- runGet ((Just <$> exifHeader) <|> return Nothing)
-- which would prevent pandoc from raising an error when an exif header can't
-- be parsed. But we only get an Alternative instance for Get in binary 0.6,
-- and binary 0.5 ships with ghc 7.6.
-exifHeader :: BL.ByteString -> Get ImageSize
+exifHeader :: BL.ByteString -> ExceptT String Get ImageSize
exifHeader hdr = do
- _app1DataSize <- getWord16be
- exifHdr <- getWord32be
- unless (exifHdr == 0x45786966) $ fail "Did not find exif header"
- zeros <- getWord16be
- unless (zeros == 0) $ fail "Expected zeros after exif header"
+ _app1DataSize <- lift getWord16be
+ exifHdr <- lift getWord32be
+ unless (exifHdr == 0x45786966) $ throwError "Did not find exif header"
+ zeros <- lift getWord16be
+ unless (zeros == 0) $ throwError "Expected zeros after exif header"
-- beginning of tiff header -- we read whole thing to use
-- in getting data from offsets:
let tiffHeader = BL.drop 8 hdr
- byteAlign <- getWord16be
+ byteAlign <- lift getWord16be
let bigEndian = byteAlign == 0x4d4d
let (getWord16, getWord32, getWord64) =
if bigEndian
@@ -213,48 +236,53 @@ exifHeader hdr = do
num <- getWord32
den <- getWord32
return $ fromIntegral num / fromIntegral den
- tagmark <- getWord16
- unless (tagmark == 0x002a) $ fail "Failed alignment sanity check"
- ifdOffset <- getWord32
- skip (fromIntegral ifdOffset - 8) -- skip to IDF
- numentries <- getWord16
- let ifdEntry = do
- tag <- getWord16 >>= \t ->
- maybe (return UnknownTagType) return
- (M.lookup t tagTypeTable)
- dataFormat <- getWord16
- numComponents <- getWord32
+ tagmark <- lift getWord16
+ unless (tagmark == 0x002a) $ throwError "Failed alignment sanity check"
+ ifdOffset <- lift getWord32
+ lift $ skip (fromIntegral ifdOffset - 8) -- skip to IDF
+ numentries <- lift getWord16
+ let ifdEntry :: ExceptT String Get (TagType, DataFormat)
+ ifdEntry = do
+ tag <- fromMaybe UnknownTagType . flip M.lookup tagTypeTable
+ <$> lift getWord16
+ dataFormat <- lift getWord16
+ numComponents <- lift getWord32
(fmt, bytesPerComponent) <-
case dataFormat of
- 1 -> return (UnsignedByte . runGet getWord8, 1)
- 2 -> return (AsciiString, 1)
- 3 -> return (UnsignedShort . runGet getWord16, 2)
- 4 -> return (UnsignedLong . runGet getWord32, 4)
- 5 -> return (UnsignedRational . runGet getRational, 8)
- 6 -> return (SignedByte . runGet getWord8, 1)
- 7 -> return (Undefined . runGet getWord8, 1)
- 8 -> return (SignedShort . runGet getWord16, 2)
- 9 -> return (SignedLong . runGet getWord32, 4)
- 10 -> return (SignedRational . runGet getRational, 8)
- 11 -> return (SingleFloat . runGet getWord32 {- TODO -}, 4)
- 12 -> return (DoubleFloat . runGet getWord64 {- TODO -}, 8)
- _ -> fail $ "Unknown data format " ++ show dataFormat
+ 1 -> return (UnsignedByte <$> getWord8, 1)
+ 2 -> return (AsciiString <$>
+ getLazyByteString
+ (fromIntegral numComponents), 1)
+ 3 -> return (UnsignedShort <$> getWord16, 2)
+ 4 -> return (UnsignedLong <$> getWord32, 4)
+ 5 -> return (UnsignedRational <$> getRational, 8)
+ 6 -> return (SignedByte <$> getWord8, 1)
+ 7 -> return (Undefined <$> getLazyByteString
+ (fromIntegral numComponents), 1)
+ 8 -> return (SignedShort <$> getWord16, 2)
+ 9 -> return (SignedLong <$> getWord32, 4)
+ 10 -> return (SignedRational <$> getRational, 8)
+ 11 -> return (SingleFloat <$> getWord32 {- TODO -}, 4)
+ 12 -> return (DoubleFloat <$> getWord64 {- TODO -}, 8)
+ _ -> throwError $ "Unknown data format " ++ show dataFormat
let totalBytes = fromIntegral $ numComponents * bytesPerComponent
payload <- if totalBytes <= 4 -- data is right here
- then fmt <$>
- (getLazyByteString (fromIntegral totalBytes) <*
- skip (4 - totalBytes))
+ then lift $ fmt <* skip (4 - totalBytes)
else do -- get data from offset
- offs <- getWord32
- return $ fmt $ BL.take (fromIntegral totalBytes) $
- BL.drop (fromIntegral offs) tiffHeader
+ offs <- lift getWord32
+ let bytesAtOffset =
+ BL.take (fromIntegral totalBytes)
+ $ BL.drop (fromIntegral offs) tiffHeader
+ case runGet' (Right <$> fmt) bytesAtOffset of
+ Left msg -> throwError msg
+ Right x -> return x
return (tag, payload)
entries <- sequence $ replicate (fromIntegral numentries) ifdEntry
subentries <- case lookup ExifOffset entries of
Just (UnsignedLong offset) -> do
- pos <- bytesRead
- skip (fromIntegral offset - (fromIntegral pos - 8))
- numsubentries <- getWord16
+ pos <- lift bytesRead
+ lift $ skip (fromIntegral offset - (fromIntegral pos - 8))
+ numsubentries <- lift getWord16
sequence $
replicate (fromIntegral numsubentries) ifdEntry
_ -> return []
@@ -285,7 +313,7 @@ data DataFormat = UnsignedByte Word8
| UnsignedLong Word32
| UnsignedRational Rational
| SignedByte Word8
- | Undefined Word8
+ | Undefined BL.ByteString
| SignedShort Word16
| SignedLong Word32
| SignedRational Rational
diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs
index 75b4ff0d2..6fd9ac373 100644
--- a/src/Text/Pandoc/MIME.hs
+++ b/src/Text/Pandoc/MIME.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.MIME
- Copyright : Copyright (C) 2011-2014 John MacFarlane
+ Copyright : Copyright (C) 2011-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -328,7 +328,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("oth","application/vnd.oasis.opendocument.text-web")
,("otp","application/vnd.oasis.opendocument.presentation-template")
,("ots","application/vnd.oasis.opendocument.spreadsheet-template")
- ,("otf","application/x-font-opentype")
+ ,("otf","application/vnd.ms-opentype")
,("ott","application/vnd.oasis.opendocument.text-template")
,("oza","application/x-oz-application")
,("p","text/x-pascal")
@@ -433,7 +433,9 @@ mimeTypesList = -- List borrowed from happstack-server.
,("sv4cpio","application/x-sv4cpio")
,("sv4crc","application/x-sv4crc")
,("svg","image/svg+xml")
- ,("svgz","image/svg+xml")
+ -- removed for now, since it causes problems with
+ -- extensionFromMimeType: see #2183.
+ -- ,("svgz","image/svg+xml")
,("sw","chemical/x-swissprot")
,("swf","application/x-shockwave-flash")
,("swfl","application/x-shockwave-flash")
@@ -497,6 +499,7 @@ mimeTypesList = -- List borrowed from happstack-server.
,("wmx","video/x-ms-wmx")
,("wmz","application/x-ms-wmz")
,("woff","application/x-font-woff")
+ ,("woff2","application/x-font-woff2")
,("wp5","application/wordperfect5.1")
,("wpd","application/wordperfect")
,("wrl","model/vrml")
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index a55d5417e..1246cdc8f 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
{-
Copyright (C) 2014 John MacFarlane <jgm@berkeley.edu>
@@ -46,13 +46,15 @@ import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
import qualified Text.Pandoc.UTF8 as UTF8
import Data.Maybe (fromMaybe)
import System.IO (stderr)
+import Data.Data (Data)
+import Data.Typeable (Typeable)
-- | A container for a collection of binary resources, with names and
-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
-- can be used for an empty 'MediaBag', and '<>' can be used to append
-- two 'MediaBag's.
newtype MediaBag = MediaBag (M.Map [String] (MimeType, BL.ByteString))
- deriving (Monoid)
+ deriving (Monoid, Data, Typeable)
instance Show MediaBag where
show bag = "MediaBag " ++ show (mediaDirectory bag)
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index ebfd8f8a9..17eb4a15c 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE DeriveDataTypeable #-}
{-
-Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Options
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ options.
-}
module Text.Pandoc.Options ( Extension(..)
, pandocExtensions
+ , plainExtensions
, strictExtensions
, phpMarkdownExtraExtensions
, githubMarkdownExtensions
@@ -51,6 +53,8 @@ import Data.Default
import Text.Pandoc.Highlighting (Style, pygments)
import Text.Pandoc.MediaBag (MediaBag)
import Data.Monoid
+import Data.Data (Data)
+import Data.Typeable (Typeable)
-- | Individually selectable syntax extensions.
data Extension =
@@ -74,7 +78,7 @@ data Extension =
| 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_backtick_code_blocks -- ^ GitHub style ``` code blocks
| Ext_inline_code_attributes -- ^ Allow attributes on inline code
| Ext_markdown_in_html_blocks -- ^ Interpret as markdown inside HTML blocks
| Ext_native_divs -- ^ Use Div blocks for contents of <div> tags
@@ -109,7 +113,8 @@ data Extension =
| Ext_implicit_header_references -- ^ Implicit reference links for headers
| Ext_line_blocks -- ^ RST style line blocks
| Ext_epub_html_exts -- ^ Recognise the EPUB extended version of HTML
- deriving (Show, Read, Enum, Eq, Ord, Bounded)
+ | Ext_shortcut_reference_links -- ^ Shortcut reference links
+ deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable)
pandocExtensions :: Set Extension
pandocExtensions = Set.fromList
@@ -151,6 +156,25 @@ pandocExtensions = Set.fromList
, Ext_header_attributes
, Ext_implicit_header_references
, Ext_line_blocks
+ , Ext_shortcut_reference_links
+ ]
+
+plainExtensions :: Set Extension
+plainExtensions = Set.fromList
+ [ Ext_table_captions
+ , Ext_implicit_figures
+ , Ext_simple_tables
+ , Ext_multiline_tables
+ , Ext_grid_tables
+ , Ext_latex_macros
+ , Ext_fancy_lists
+ , Ext_startnum
+ , Ext_definition_lists
+ , Ext_example_lists
+ , Ext_intraword_underscores
+ , Ext_blank_before_blockquote
+ , Ext_blank_before_header
+ , Ext_strikeout
]
phpMarkdownExtraExtensions :: Set Extension
@@ -164,6 +188,7 @@ phpMarkdownExtraExtensions = Set.fromList
, Ext_intraword_underscores
, Ext_header_attributes
, Ext_abbreviations
+ , Ext_shortcut_reference_links
]
githubMarkdownExtensions :: Set Extension
@@ -180,6 +205,7 @@ githubMarkdownExtensions = Set.fromList
, Ext_strikeout
, Ext_hard_line_breaks
, Ext_lists_without_preceding_blankline
+ , Ext_shortcut_reference_links
]
multimarkdownExtensions :: Set Extension
@@ -202,7 +228,9 @@ multimarkdownExtensions = Set.fromList
strictExtensions :: Set Extension
strictExtensions = Set.fromList
- [ Ext_raw_html ]
+ [ Ext_raw_html
+ , Ext_shortcut_reference_links
+ ]
data ReaderOptions = ReaderOptions{
readerExtensions :: Set Extension -- ^ Syntax extensions
@@ -220,7 +248,7 @@ data ReaderOptions = ReaderOptions{
, readerDefaultImageExtension :: String -- ^ Default extension for images
, readerTrace :: Bool -- ^ Print debugging info
, readerTrackChanges :: TrackChanges
-} deriving (Show, Read)
+} deriving (Show, Read, Data, Typeable)
instance Default ReaderOptions
where def = ReaderOptions{
@@ -242,7 +270,7 @@ instance Default ReaderOptions
-- Writer options
--
-data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read)
+data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable)
data HTMLMathMethod = PlainMath
| LaTeXMathML (Maybe String) -- url of LaTeXMathML.js
@@ -252,18 +280,18 @@ data HTMLMathMethod = PlainMath
| MathML (Maybe String) -- url of MathMLinHTML.js
| MathJax String -- url of MathJax.js
| KaTeX String String -- url of stylesheet and katex.js
- deriving (Show, Read, Eq)
+ deriving (Show, Read, Eq, Data, Typeable)
data CiteMethod = Citeproc -- use citeproc to render them
| Natbib -- output natbib cite commands
| Biblatex -- output biblatex cite commands
- deriving (Show, Read, Eq)
+ deriving (Show, Read, Eq, Data, Typeable)
-- | Methods for obfuscating email addresses in HTML.
data ObfuscationMethod = NoObfuscation
| ReferenceObfuscation
| JavascriptObfuscation
- deriving (Show, Read, Eq)
+ deriving (Show, Read, Eq, Data, Typeable)
-- | Varieties of HTML slide shows.
data HTMLSlideVariant = S5Slides
@@ -272,13 +300,13 @@ data HTMLSlideVariant = S5Slides
| DZSlides
| RevealJsSlides
| NoSlides
- deriving (Show, Read, Eq)
+ deriving (Show, Read, Eq, Data, Typeable)
-- | Options for accepting or rejecting MS Word track-changes.
data TrackChanges = AcceptChanges
| RejectChanges
| AllChanges
- deriving (Show, Read, Eq)
+ deriving (Show, Read, Eq, Data, Typeable)
-- | Options for writers
data WriterOptions = WriterOptions
@@ -323,7 +351,9 @@ data WriterOptions = WriterOptions
, writerReferenceODT :: Maybe FilePath -- ^ Path to reference ODT if specified
, writerReferenceDocx :: Maybe FilePath -- ^ Path to reference DOCX if specified
, writerMediaBag :: MediaBag -- ^ Media collected by docx or epub reader
- } deriving Show
+ , writerVerbose :: Bool -- ^ Verbose debugging output
+ , writerLaTeXArgs :: [String] -- ^ Flags to pass to latex-engine
+ } deriving (Show, Data, Typeable)
instance Default WriterOptions where
def = WriterOptions { writerStandalone = False
@@ -366,6 +396,8 @@ instance Default WriterOptions where
, writerReferenceODT = Nothing
, writerReferenceDocx = Nothing
, writerMediaBag = mempty
+ , writerVerbose = False
+ , writerLaTeXArgs = []
}
-- | Returns True if the given extension is enabled.
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index d5f7c609d..8f92a3321 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings, CPP, ScopedTypeVariables #-}
{-
-Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.PDF
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -36,10 +36,11 @@ import qualified Data.ByteString.Lazy.Char8 as BC
import qualified Data.ByteString as BS
import System.Exit (ExitCode (..))
import System.FilePath
+import System.IO (stderr, stdout)
import System.Directory
import Data.Digest.Pure.SHA (showDigest, sha1)
import System.Environment
-import Control.Monad (unless, (<=<))
+import Control.Monad (unless, when, (<=<))
import qualified Control.Exception as E
import Control.Applicative ((<$))
import Data.List (isInfixOf)
@@ -70,7 +71,8 @@ makePDF :: String -- ^ pdf creator (pdflatex, lualatex, xelatex)
makePDF program writer opts doc = withTempDir "tex2pdf." $ \tmpdir -> do
doc' <- handleImages opts tmpdir doc
let source = writer opts doc'
- tex2pdf' tmpdir program source
+ args = writerLaTeXArgs opts
+ tex2pdf' (writerVerbose opts) args tmpdir program source
handleImages :: WriterOptions
-> FilePath -- ^ temp dir to store images
@@ -106,8 +108,7 @@ convertImages tmpdir (Image ils (src, tit)) = do
img <- convertImage tmpdir src
newPath <-
case img of
- Left e -> src <$
- warn ("Unable to convert image `" ++ src ++ "':\n" ++ e)
+ Left e -> src <$ warn e
Right fp -> return fp
return (Image ils (newPath, tit))
convertImages _ x = return x
@@ -121,7 +122,8 @@ convertImage tmpdir fname =
Just "application/pdf" -> doNothing
_ -> JP.readImage fname >>= \res ->
case res of
- Left msg -> return $ Left msg
+ Left _ -> return $ Left $ "Unable to convert `" ++
+ fname ++ "' for use with pdflatex."
Right img ->
E.catch (Right fileOut <$ JP.savePngImage fileOut img) $
\(e :: E.SomeException) -> return (Left (show e))
@@ -130,22 +132,25 @@ convertImage tmpdir fname =
mime = getMimeType fname
doNothing = return (Right fname)
-tex2pdf' :: FilePath -- ^ temp directory for output
+tex2pdf' :: Bool -- ^ Verbose output
+ -> [String] -- ^ Arguments to the latex-engine
+ -> FilePath -- ^ temp directory for output
-> String -- ^ tex program
-> String -- ^ tex source
-> IO (Either ByteString ByteString)
-tex2pdf' tmpDir program source = do
+tex2pdf' verbose args tmpDir program source = do
let numruns = if "\\tableofcontents" `isInfixOf` source
then 3 -- to get page numbers
else 2 -- 1 run won't give you PDF bookmarks
- (exit, log', mbPdf) <- runTeXProgram program numruns tmpDir source
+ (exit, log', mbPdf) <- runTeXProgram verbose program args 1 numruns tmpDir source
case (exit, mbPdf) of
(ExitFailure _, _) -> do
let logmsg = extractMsg log'
let extramsg =
case logmsg of
- x | "! Package inputenc Error" `BC.isPrefixOf` x ->
- "\nTry running pandoc with --latex-engine=xelatex."
+ x | ("! Package inputenc Error" `BC.isPrefixOf` x
+ && program /= "xelatex")
+ -> "\nTry running pandoc with --latex-engine=xelatex."
_ -> ""
return $ Left $ logmsg <> extramsg
(ExitSuccess, Nothing) -> return $ Left ""
@@ -170,9 +175,9 @@ extractMsg log' = do
-- Run a TeX program on an input bytestring and return (exit code,
-- contents of stdout, contents of produced PDF if any). Rerun
-- a fixed number of times to resolve references.
-runTeXProgram :: String -> Int -> FilePath -> String
+runTeXProgram :: Bool -> String -> [String] -> Int -> Int -> FilePath -> String
-> IO (ExitCode, ByteString, Maybe ByteString)
-runTeXProgram program runsLeft tmpDir source = do
+runTeXProgram verbose program args runNumber numRuns tmpDir source = do
let file = tmpDir </> "input.tex"
exists <- doesFileExist file
unless exists $ UTF8.writeFile file source
@@ -185,16 +190,33 @@ runTeXProgram program runsLeft tmpDir source = do
let file' = file
#endif
let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
- "-output-directory", tmpDir', file']
+ "-output-directory", tmpDir'] ++ args ++ [file']
env' <- getEnvironment
let sep = searchPathSeparator:[]
let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
$ lookup "TEXINPUTS" env'
let env'' = ("TEXINPUTS", texinputs) :
[(k,v) | (k,v) <- env', k /= "TEXINPUTS"]
+ when (verbose && runNumber == 1) $ do
+ putStrLn $ "[makePDF] temp dir:"
+ putStrLn tmpDir'
+ putStrLn $ "[makePDF] Command line:"
+ putStrLn $ program ++ " " ++ unwords (map show programArgs)
+ putStr "\n"
+ putStrLn $ "[makePDF] Environment:"
+ mapM_ print env''
+ putStr "\n"
+ putStrLn $ "[makePDF] Contents of " ++ file' ++ ":"
+ B.readFile file' >>= B.putStr
+ putStr "\n"
(exit, out, err) <- pipeProcess (Just env'') program programArgs BL.empty
- if runsLeft > 1
- then runTeXProgram program (runsLeft - 1) tmpDir source
+ when verbose $ do
+ putStrLn $ "[makePDF] Run #" ++ show runNumber
+ B.hPutStr stdout out
+ B.hPutStr stderr err
+ putStr "\n"
+ if runNumber <= numRuns
+ then runTeXProgram verbose program args (runNumber + 1) numRuns tmpDir source
else do
let pdfFile = replaceDirectory (replaceExtension file ".pdf") tmpDir
pdfExists <- doesFileExist pdfFile
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index d1fba1e21..c316e9220 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -5,7 +5,7 @@
, MultiParamTypeClasses
, FlexibleInstances #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Parsing
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -65,6 +65,7 @@ module Text.Pandoc.Parsing ( anyLine,
widthsFromIndices,
gridTableWith,
readWith,
+ readWithWarnings,
readWithM,
testStringWith,
guardEnabled,
@@ -162,6 +163,8 @@ module Text.Pandoc.Parsing ( anyLine,
setSourceColumn,
setSourceLine,
newPos,
+ addWarning,
+ (<+?>)
)
where
@@ -175,7 +178,7 @@ import Text.Parsec hiding (token)
import Text.Parsec.Pos (newPos)
import Data.Char ( toLower, toUpper, ord, chr, isAscii, isAlphaNum,
isHexDigit, isSpace )
-import Data.List ( intercalate, transpose )
+import Data.List ( intercalate, transpose, isSuffixOf )
import Text.Pandoc.Shared
import qualified Data.Map as M
import Text.TeXMath.Readers.TeX.Macros (applyMacros, Macro,
@@ -190,6 +193,8 @@ import Control.Applicative ((<$>), (<*>), (*>), (<*), (<$), Applicative)
import Data.Monoid
import Data.Maybe (catMaybes)
+import Text.Pandoc.Error
+
type Parser t s = Parsec t s
type ParserT = ParsecT
@@ -312,12 +317,14 @@ stringAnyCase (x:xs) = do
return (firstChar:rest)
-- | Parse contents of 'str' using 'parser' and return result.
-parseFromString :: Stream s m t => ParserT s st m a -> s -> ParserT s st m a
+parseFromString :: Monad m => ParserT String st m a -> String -> ParserT String st m a
parseFromString parser str = do
oldPos <- getPosition
oldInput <- getInput
setInput str
result <- parser
+ spaces
+ eof
setInput oldInput
setPosition oldPos
return result
@@ -441,18 +448,17 @@ uri :: Stream [Char] m Char => ParserT [Char] st m (String, String)
uri = try $ do
scheme <- uriScheme
char ':'
- -- We allow punctuation except at the end, since
+ -- We allow sentence punctuation except at the end, since
-- we don't want the trailing '.' in 'http://google.com.' We want to allow
-- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation)
-- as a URL, while NOT picking up the closing paren in
-- (http://wikipedia.org). So we include balanced parens in the URL.
- let isWordChar c = isAlphaNum c || c == '_' || c == '/' || c == '+' ||
- not (isAscii c)
+ let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-"
let wordChar = satisfy isWordChar
let percentEscaped = try $ char '%' >> skipMany1 (satisfy isHexDigit)
let entity = () <$ characterReference
let punct = skipMany1 (char ',')
- <|> () <$ (satisfy (\c -> not (isSpace c) && c /= '<'))
+ <|> () <$ (satisfy (\c -> not (isSpace c) && c /= '<' && c /= '>'))
let uriChunk = skipMany1 wordChar
<|> percentEscaped
<|> entity
@@ -472,7 +478,12 @@ mathInlineWith op cl = try $ do
string op
notFollowedBy space
words' <- many1Till (count 1 (noneOf " \t\n\\")
- <|> (char '\\' >> anyChar >>= \c -> return ['\\',c])
+ <|> (char '\\' >>
+ -- This next clause is needed because \text{..} can
+ -- contain $, \(\), etc.
+ (try (string "text" >>
+ (("\\text" ++) <$> inBalancedBraces 0 ""))
+ <|> (\c -> ['\\',c]) <$> anyChar))
<|> do (blankline <* notFollowedBy' blankline) <|>
(oneOf " \t" <* skipMany (oneOf " \t"))
notFollowedBy (char '$')
@@ -480,6 +491,23 @@ mathInlineWith op cl = try $ do
) (try $ string cl)
notFollowedBy digit -- to prevent capture of $5
return $ concat words'
+ where
+ inBalancedBraces :: Stream s m Char => Int -> String -> ParserT s st m String
+ inBalancedBraces 0 "" = do
+ c <- anyChar
+ if c == '{'
+ then inBalancedBraces 1 "{"
+ else mzero
+ inBalancedBraces 0 s = return $ reverse s
+ inBalancedBraces numOpen ('\\':xs) = do
+ c <- anyChar
+ inBalancedBraces numOpen (c:'\\':xs)
+ inBalancedBraces numOpen xs = do
+ c <- anyChar
+ case c of
+ '}' -> inBalancedBraces (numOpen - 1) (c:xs)
+ '{' -> inBalancedBraces (numOpen + 1) (c:xs)
+ _ -> inBalancedBraces numOpen (c:xs)
mathDisplayWith :: Stream s m Char => String -> String -> ParserT s st m String
mathDisplayWith op cl = try $ do
@@ -837,27 +865,27 @@ readWithM :: (Monad m, Functor m)
=> ParserT [Char] st m a -- ^ parser
-> st -- ^ initial state
-> String -- ^ input
- -> m a
+ -> m (Either PandocError a)
readWithM parser state input =
- handleError <$> (runParserT parser state "source" input)
- where
- handleError (Left err') =
- let errPos = errorPos err'
- errLine = sourceLine errPos
- errColumn = sourceColumn errPos
- theline = (lines input ++ [""]) !! (errLine - 1)
- in error $ "\nError at " ++ show err' ++ "\n" ++
- theline ++ "\n" ++ replicate (errColumn - 1) ' ' ++
- "^"
- handleError (Right result) = result
+ mapLeft (ParsecError input) <$> runParserT parser state "source" input
+
-- | Parse a string with a given parser and state
readWith :: Parser [Char] st a
-> st
-> String
- -> a
+ -> Either PandocError a
readWith p t inp = runIdentity $ readWithM p t inp
+readWithWarnings :: Parser [Char] ParserState a
+ -> ParserState
+ -> String
+ -> Either PandocError (a, [String])
+readWithWarnings p = readWith $ do
+ doc <- p
+ warnings <- stateWarnings <$> getState
+ return (doc, warnings)
+
-- | Parse a string with @parser@ (for testing).
testStringWith :: (Show a, Stream [Char] Identity Char)
=> ParserT [Char] ParserState Identity a
@@ -874,7 +902,8 @@ data ParserState = ParserState
stateAllowLinks :: Bool, -- ^ Allow parsing of links
stateMaxNestingLevel :: Int, -- ^ Max # of nested Strong/Emph
stateLastStrPos :: Maybe SourcePos, -- ^ Position after last str parsed
- stateKeys :: KeyTable, -- ^ List of reference keys (with fallbacks)
+ stateKeys :: KeyTable, -- ^ List of reference keys
+ stateHeaderKeys :: KeyTable, -- ^ List of implicit header ref keys
stateSubstitutions :: SubstTable, -- ^ List of substitution references
stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
@@ -888,10 +917,9 @@ data ParserState = ParserState
stateHasChapters :: Bool, -- ^ True if \chapter encountered
stateMacros :: [Macro], -- ^ List of macros defined so far
stateRstDefaultRole :: String, -- ^ Current rST default interpreted text role
- stateRstCustomRoles :: M.Map String (String, Maybe String, Attr -> (String, Attr)), -- ^ Current rST custom text roles
+ stateRstCustomRoles :: M.Map String (String, Maybe String, Attr), -- ^ Current rST custom text roles
-- Triple represents: 1) Base role, 2) Optional format (only for :raw:
- -- roles), 3) Source language annotation for code (could be used to
- -- annotate role classes too).
+ -- roles), 3) Additional classes (rest of Attr is unused)).
stateCaption :: Maybe Inlines, -- ^ Caption in current environment
stateInHtmlBlock :: Maybe String, -- ^ Tag type of HTML block being parsed
stateMarkdownAttribute :: Bool, -- ^ True if in markdown=1 context
@@ -973,6 +1001,7 @@ defaultParserState =
stateMaxNestingLevel = 6,
stateLastStrPos = Nothing,
stateKeys = M.empty,
+ stateHeaderKeys = M.empty,
stateSubstitutions = M.empty,
stateNotes = [],
stateNotes' = [],
@@ -1034,7 +1063,9 @@ type NoteTable' = [(String, F Blocks)] -- used in markdown reader
newtype Key = Key String deriving (Show, Read, Eq, Ord)
toKey :: String -> Key
-toKey = Key . map toLower . unwords . words
+toKey = Key . map toLower . unwords . words . unbracket
+ where unbracket ('[':xs) | "]" `isSuffixOf` xs = take (length xs - 1) xs
+ unbracket xs = xs
type KeyTable = M.Map Key Target
@@ -1178,7 +1209,7 @@ citeKey = try $ do
guard =<< notAfterString
suppress_author <- option False (char '-' *> return True)
char '@'
- firstChar <- letter <|> char '_'
+ firstChar <- alphaNum <|> char '_' <|> char '*' -- @* for wildcard in nocite
let regchar = satisfy (\c -> isAlphaNum c || c == '_')
let internal p = try $ p <* lookAhead regchar
rest <- many $ regchar <|> internal (oneOf ":.#$%&-+?<>~/")
@@ -1223,3 +1254,13 @@ applyMacros' target = do
then do macros <- extractMacros <$> getState
return $ applyMacros macros target
else return target
+
+-- | Append a warning to the log.
+addWarning :: Maybe SourcePos -> String -> Parser [Char] ParserState ()
+addWarning mbpos msg =
+ updateState $ \st -> st{
+ stateWarnings = (msg ++ maybe "" (\pos -> " " ++ show pos) mbpos) :
+ stateWarnings st }
+infixr 5 <+?>
+(<+?>) :: (Monoid a, Monad m) => ParserT s st m a -> ParserT s st m a -> ParserT s st m a
+a <+?> b = a >>= flip fmap (try b <|> return mempty) . (<>)
diff --git a/src/Text/Pandoc/Pretty.hs b/src/Text/Pandoc/Pretty.hs
index 1e72c2040..5e6450746 100644
--- a/src/Text/Pandoc/Pretty.hs
+++ b/src/Text/Pandoc/Pretty.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE GeneralizedNewtypeDeriving, CPP #-}
{-
-Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111(-1)307 USA
{- |
Module : Text.Pandoc.Pretty
- Copyright : Copyright (C) 2010-2014 John MacFarlane
+ Copyright : Copyright (C) 2010-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -250,6 +250,11 @@ renderDoc :: (IsString a, Monoid a)
=> Doc -> DocState a
renderDoc = renderList . toList . unDoc
+data IsBlock = IsBlock Int [String]
+
+-- This would be nicer with a pattern synonym
+-- pattern VBlock i s <- mkIsBlock -> Just (IsBlock ..)
+
renderList :: (IsString a, Monoid a)
=> [D] -> DocState a
renderList [] = return ()
@@ -286,6 +291,9 @@ renderList (BlankLines num : xs) = do
| otherwise -> replicateM_ (1 + num - newlines st) (outp (-1) "\n")
renderList xs
+renderList (CarriageReturn : BlankLines m : xs) =
+ renderList (BlankLines m : xs)
+
renderList (CarriageReturn : xs) = do
st <- get
if newlines st > 0 || null xs
@@ -320,11 +328,11 @@ renderList (BreakingSpace : xs) = do
outp 1 " "
renderList xs'
-renderList (b1@Block{} : b2@Block{} : xs) =
- renderList (mergeBlocks False b1 b2 : xs)
+renderList (Block i1 s1 : Block i2 s2 : xs) =
+ renderList (mergeBlocks False (IsBlock i1 s1) (IsBlock i2 s2) : xs)
-renderList (b1@Block{} : BreakingSpace : b2@Block{} : xs) =
- renderList (mergeBlocks True b1 b2 : xs)
+renderList (Block i1 s1 : BreakingSpace : Block i2 s2 : xs) =
+ renderList (mergeBlocks True (IsBlock i1 s1) (IsBlock i2 s2) : xs)
renderList (Block width lns : xs) = do
st <- get
@@ -336,15 +344,14 @@ renderList (Block width lns : xs) = do
modify $ \s -> s{ prefix = oldPref }
renderList xs
-mergeBlocks :: Bool -> D -> D -> D
-mergeBlocks addSpace (Block w1 lns1) (Block w2 lns2) =
+mergeBlocks :: Bool -> IsBlock -> IsBlock -> D
+mergeBlocks addSpace (IsBlock w1 lns1) (IsBlock w2 lns2) =
Block (w1 + w2 + if addSpace then 1 else 0) $
zipWith (\l1 l2 -> pad w1 l1 ++ l2) (lns1 ++ empties) (map sp lns2 ++ empties)
where empties = replicate (abs $ length lns1 - length lns2) ""
pad n s = s ++ replicate (n - realLength s) ' '
sp "" = ""
sp xs = if addSpace then (' ' : xs) else xs
-mergeBlocks _ _ _ = error "mergeBlocks tried on non-Block!"
blockToDoc :: Int -> [String] -> Doc
blockToDoc _ lns = text $ intercalate "\n" lns
@@ -531,4 +538,4 @@ charWidth c =
-- | Get real length of string, taking into account combining and double-wide
-- characters.
realLength :: String -> Int
-realLength = sum . map charWidth
+realLength = foldr (\a b -> charWidth a + b) 0
diff --git a/src/Text/Pandoc/Process.hs b/src/Text/Pandoc/Process.hs
index 19872b405..e5245638d 100644
--- a/src/Text/Pandoc/Process.hs
+++ b/src/Text/Pandoc/Process.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Process
- Copyright : Copyright (C) 2013-2014 John MacFarlane
+ Copyright : Copyright (C) 2013-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
new file mode 100644
index 000000000..51a35c8ad
--- /dev/null
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -0,0 +1,119 @@
+{-
+Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.CommonMark
+ Copyright : Copyright (C) 2015 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of CommonMark-formatted plain text to 'Pandoc' document.
+
+CommonMark is a strongly specified variant of Markdown: http://commonmark.org.
+-}
+module Text.Pandoc.Readers.CommonMark (readCommonMark)
+where
+
+import CMark
+import Data.Text (unpack, pack)
+import Data.List (groupBy)
+import Text.Pandoc.Definition
+import Text.Pandoc.Options
+import Text.Pandoc.Error
+
+-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
+readCommonMark :: ReaderOptions -> String -> Either PandocError Pandoc
+readCommonMark opts = Right . nodeToPandoc . commonmarkToNode opts' . pack
+ where opts' = if readerSmart opts
+ then [optNormalize, optSmart]
+ else [optNormalize]
+
+nodeToPandoc :: Node -> Pandoc
+nodeToPandoc (Node _ DOCUMENT nodes) =
+ Pandoc nullMeta $ foldr addBlock [] nodes
+nodeToPandoc n = -- shouldn't happen
+ Pandoc nullMeta $ foldr addBlock [] [n]
+
+addBlocks :: [Node] -> [Block]
+addBlocks = foldr addBlock []
+
+addBlock :: Node -> [Block] -> [Block]
+addBlock (Node _ PARAGRAPH nodes) =
+ (Para (addInlines nodes) :)
+addBlock (Node _ HRULE _) =
+ (HorizontalRule :)
+addBlock (Node _ BLOCK_QUOTE nodes) =
+ (BlockQuote (addBlocks nodes) :)
+addBlock (Node _ (HTML t) _) =
+ (RawBlock (Format "html") (unpack t) :)
+addBlock (Node _ (CODE_BLOCK info t) _) =
+ (CodeBlock ("", take 1 (words (unpack info)), []) (unpack t) :)
+addBlock (Node _ (HEADER lev) nodes) =
+ (Header lev ("",[],[]) (addInlines nodes) :)
+addBlock (Node _ (LIST listAttrs) nodes) =
+ (constructor (map (setTightness . addBlocks . children) nodes) :)
+ where constructor = case listType listAttrs of
+ BULLET_LIST -> BulletList
+ ORDERED_LIST -> OrderedList
+ (start, DefaultStyle, delim)
+ start = listStart listAttrs
+ setTightness = if listTight listAttrs
+ then map paraToPlain
+ else id
+ paraToPlain (Para xs) = Plain (xs)
+ paraToPlain x = x
+ delim = case listDelim listAttrs of
+ PERIOD_DELIM -> Period
+ PAREN_DELIM -> OneParen
+addBlock (Node _ ITEM _) = id -- handled in LIST
+addBlock _ = id
+
+children :: Node -> [Node]
+children (Node _ _ ns) = ns
+
+addInlines :: [Node] -> [Inline]
+addInlines = foldr addInline []
+
+addInline :: Node -> [Inline] -> [Inline]
+addInline (Node _ (TEXT t) _) = (map toinl clumps ++)
+ where raw = unpack t
+ clumps = groupBy samekind raw
+ samekind ' ' ' ' = True
+ samekind ' ' _ = False
+ samekind _ ' ' = False
+ samekind _ _ = True
+ toinl (' ':_) = Space
+ toinl xs = Str xs
+addInline (Node _ LINEBREAK _) = (LineBreak :)
+addInline (Node _ SOFTBREAK _) = (Space :)
+addInline (Node _ (INLINE_HTML t) _) =
+ (RawInline (Format "html") (unpack t) :)
+addInline (Node _ (CODE t) _) =
+ (Code ("",[],[]) (unpack t) :)
+addInline (Node _ EMPH nodes) =
+ (Emph (addInlines nodes) :)
+addInline (Node _ STRONG nodes) =
+ (Strong (addInlines nodes) :)
+addInline (Node _ (LINK url title) nodes) =
+ (Link (addInlines nodes) (unpack url, unpack title) :)
+addInline (Node _ (IMAGE url title) nodes) =
+ (Image (addInlines nodes) (unpack url, unpack title) :)
+addInline _ = id
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
index 59ff3e717..3cc2a4479 100644
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -15,6 +15,9 @@ import Control.Applicative ((<$>))
import Data.List (intersperse)
import Data.Maybe (fromMaybe)
import Text.TeXMath (readMathML, writeTeX)
+import Text.Pandoc.Error (PandocError)
+import Text.Pandoc.Compat.Except
+import Data.Default
{-
@@ -70,8 +73,8 @@ List of all DocBook tags, with [x] indicating implemented,
[x] book - A book
[x] bookinfo - Meta-information for a Book
[x] bridgehead - A free-floating heading
-[ ] callout - A “called out” description of a marked Area
-[ ] calloutlist - A list of Callouts
+[x] callout - A “called out” description of a marked Area
+[x] calloutlist - A list of Callouts
[x] caption - A caption
[x] caution - A note of caution
[x] chapter - A chapter, as of a book
@@ -81,7 +84,7 @@ List of all DocBook tags, with [x] indicating implemented,
[ ] citerefentry - A citation to a reference page
[ ] citetitle - The title of a cited work
[ ] city - The name of a city in an address
-[ ] classname - The name of a class, in the object-oriented programming sense
+[x] classname - The name of a class, in the object-oriented programming sense
[ ] classsynopsis - The syntax summary for a class definition
[ ] classsynopsisinfo - Information supplementing the contents of
a ClassSynopsis
@@ -164,21 +167,24 @@ List of all DocBook tags, with [x] indicating implemented,
[x] glossseealso - A cross-reference from one GlossEntry to another
[x] glossterm - A glossary term
[ ] graphic - A displayed graphical object (not an inline)
+ Note: in DocBook v5 `graphic` is discarded
[ ] graphicco - A graphic that contains callout areas
+ Note: in DocBook v5 `graphicco` is discarded
[ ] group - A group of elements in a CmdSynopsis
[ ] guibutton - The text on a button in a GUI
[ ] guiicon - Graphic and/or text appearing as a icon in a GUI
[ ] guilabel - The text of a label in a GUI
-[ ] guimenu - The name of a menu in a GUI
-[ ] guimenuitem - The name of a terminal menu item in a GUI
-[ ] guisubmenu - The name of a submenu in a GUI
+[x] guimenu - The name of a menu in a GUI
+[x] guimenuitem - The name of a terminal menu item in a GUI
+[x] guisubmenu - The name of a submenu in a GUI
[ ] hardware - A physical part of a computer system
[ ] highlights - A summary of the main points of the discussed component
[ ] holder - The name of the individual or organization that holds a copyright
[o] honorific - The title of a person
[ ] html:form - An HTML form
-[ ] imagedata - Pointer to external image data
-[ ] imageobject - A wrapper for image data and its associated meta-information
+[x] imagedata - Pointer to external image data (only `fileref` attribute
+ implemented but not `entityref` which would require parsing of the DTD)
+[x] imageobject - A wrapper for image data and its associated meta-information
[ ] imageobjectco - A wrapper for an image object with callouts
[x] important - An admonition set off from the text
[x] index - An index
@@ -206,10 +212,10 @@ List of all DocBook tags, with [x] indicating implemented,
other dingbat
[ ] itermset - A set of index terms in the meta-information of a document
[ ] jobtitle - The title of an individual in an organization
-[ ] keycap - The text printed on a key on a keyboard
+[x] keycap - The text printed on a key on a keyboard
[ ] keycode - The internal, frequently numeric, identifier for a key
on a keyboard
-[ ] keycombo - A combination of input actions
+[x] keycombo - A combination of input actions
[ ] keysym - The symbolic name of a key on a keyboard
[ ] keyword - One of a set of keywords describing the content of a document
[ ] keywordset - A set of keywords describing the content of a document
@@ -237,7 +243,7 @@ List of all DocBook tags, with [x] indicating implemented,
[x] mediaobject - A displayed media object (video, audio, image, etc.)
[ ] mediaobjectco - A media object that contains callouts
[x] member - An element of a simple list
-[ ] menuchoice - A selection or series of selections from a menu
+[x] menuchoice - A selection or series of selections from a menu
[ ] methodname - The name of a method
[ ] methodparam - Parameters to a method
[ ] methodsynopsis - A syntax summary for a method
@@ -471,7 +477,7 @@ List of all DocBook tags, with [x] indicating implemented,
[ ] token - A unit of information
[x] tr - A row in an HTML table
[ ] trademark - A trademark
-[ ] type - The classification of a value
+[x] type - The classification of a value
[x] ulink - A link that addresses its target by means of a URL
(Uniform Resource Locator)
[x] uri - A Uniform Resource Identifier
@@ -497,7 +503,7 @@ List of all DocBook tags, with [x] indicating implemented,
[x] ?asciidoc-br? - line break from asciidoc docbook output
-}
-type DB = State DBState
+type DB = ExceptT PandocError (State DBState)
data DBState = DBState{ dbSectionLevel :: Int
, dbQuoteType :: QuoteType
@@ -507,16 +513,18 @@ data DBState = DBState{ dbSectionLevel :: Int
, dbFigureTitle :: Inlines
} deriving Show
-readDocBook :: ReaderOptions -> String -> Pandoc
-readDocBook _ inp = Pandoc (dbMeta st') (toList $ mconcat bs)
- where (bs, st') = runState (mapM parseBlock $ normalizeTree $ parseXML inp')
- DBState{ dbSectionLevel = 0
- , dbQuoteType = DoubleQuote
- , dbMeta = mempty
- , dbAcceptsMeta = False
- , dbBook = False
- , dbFigureTitle = mempty
- }
+instance Default DBState where
+ def = DBState{ dbSectionLevel = 0
+ , dbQuoteType = DoubleQuote
+ , dbMeta = mempty
+ , dbAcceptsMeta = False
+ , dbBook = False
+ , dbFigureTitle = mempty }
+
+
+readDocBook :: ReaderOptions -> String -> Either PandocError Pandoc
+readDocBook _ inp = (\blocks -> Pandoc (dbMeta st') (toList . mconcat $ blocks)) <$> bs
+ where (bs , st') = flip runState def . runExceptT . mapM parseBlock . normalizeTree . parseXML $ inp'
inp' = handleInstructions inp
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
@@ -603,7 +611,7 @@ isBlockElement (Elem e) = qName (elName e) `elem` blocktags
"important","caution","note","tip","warning","qandadiv",
"question","answer","abstract","itemizedlist","orderedlist",
"variablelist","article","book","table","informaltable",
- "screen","programlisting","example"]
+ "screen","programlisting","example","calloutlist"]
isBlockElement _ = False
-- Trim leading and trailing newline characters
@@ -622,18 +630,24 @@ addToStart toadd bs =
-- function that is used by both mediaobject (in parseBlock)
-- and inlinemediaobject (in parseInline)
-getImage :: Element -> DB Inlines
-getImage e = do
+-- A DocBook mediaobject is a wrapper around a set of alternative presentations
+getMediaobject :: Element -> DB Inlines
+getMediaobject e = do
imageUrl <- case filterChild (named "imageobject") e of
Nothing -> return mempty
Just z -> case filterChild (named "imagedata") z of
Nothing -> return mempty
Just i -> return $ attrValue "fileref" i
- caption <- case filterChild
- (\x -> named "caption" x || named "textobject" x) e of
- Nothing -> gets dbFigureTitle
- Just z -> mconcat <$> (mapM parseInline $ elContent z)
- return $ image imageUrl "" caption
+ let getCaption el = case filterChild (\x -> named "caption" x
+ || named "textobject" x
+ || named "alt" x) el of
+ Nothing -> return mempty
+ Just z -> mconcat <$> (mapM parseInline $ elContent z)
+ figTitle <- gets dbFigureTitle
+ let (caption, title) = if isNull figTitle
+ then (getCaption e, "")
+ else (return figTitle, "fig:")
+ liftM (image imageUrl title) caption
getBlocks :: Element -> DB Blocks
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
@@ -712,6 +726,7 @@ parseBlock (Elem e) =
"question" -> addToStart (strong (str "Q:") <> str " ") <$> getBlocks e
"answer" -> addToStart (strong (str "A:") <> str " ") <$> getBlocks e
"abstract" -> blockQuote <$> getBlocks e
+ "calloutlist" -> bulletList <$> callouts
"itemizedlist" -> bulletList <$> listitems
"orderedlist" -> do
let listStyle = case attrValue "numeration" e of
@@ -728,7 +743,7 @@ parseBlock (Elem e) =
<$> listitems
"variablelist" -> definitionList <$> deflistitems
"figure" -> getFigure e
- "mediaobject" -> para <$> getImage e
+ "mediaobject" -> para <$> getMediaobject e
"caption" -> return mempty
"info" -> metaBlock
"articleinfo" -> metaBlock
@@ -772,11 +787,6 @@ parseBlock (Elem e) =
x -> [x]
return $ codeBlockWith (attrValue "id" e, classes', [])
$ trimNl $ strContentRecursive e
- strContentRecursive = strContent . (\e' -> e'{ elContent =
- map elementToStr $ elContent e' })
- elementToStr :: Content -> Content
- elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
- elementToStr x = x
parseBlockquote = do
attrib <- case filterChild (named "attribution") e of
Nothing -> return mempty
@@ -785,6 +795,7 @@ parseBlock (Elem e) =
contents <- getBlocks e
return $ blockQuote (contents <> attrib)
listitems = mapM getBlocks $ filterChildren (named "listitem") e
+ callouts = mapM getBlocks $ filterChildren (named "callout") e
deflistitems = mapM parseVarListEntry $ filterChildren
(named "varlistentry") e
parseVarListEntry e' = do
@@ -866,18 +877,29 @@ parseBlock (Elem e) =
parseRow = mapM (parseMixed plain . elContent) . filterChildren isEntry
sect n = do isbook <- gets dbBook
let n' = if isbook || n == 0 then n + 1 else n
- headerText <- case filterChild (named "title") e of
+ headerText <- case filterChild (named "title") e `mplus`
+ (filterChild (named "info") e >>=
+ filterChild (named "title")) of
Just t -> getInlines t
Nothing -> return mempty
modify $ \st -> st{ dbSectionLevel = n }
b <- getBlocks e
+ let ident = attrValue "id" e
modify $ \st -> st{ dbSectionLevel = n - 1 }
- return $ header n' headerText <> b
+ return $ headerWith (ident,[],[]) n' headerText <> b
metaBlock = acceptingMetadata (getBlocks e) >> return mempty
getInlines :: Element -> DB Inlines
getInlines e' = (trimInlines . mconcat) <$> (mapM parseInline $ elContent e')
+strContentRecursive :: Element -> String
+strContentRecursive = strContent .
+ (\e' -> e'{ elContent = map elementToStr $ elContent e' })
+
+elementToStr :: Content -> Content
+elementToStr (Elem e') = Text $ CData CDataText (strContentRecursive e') Nothing
+elementToStr x = x
+
parseInline :: Content -> DB Inlines
parseInline (Text (CData _ s _)) = return $ text s
parseInline (CRef ref) =
@@ -889,7 +911,7 @@ parseInline (Elem e) =
"inlineequation" -> equation math
"subscript" -> subscript <$> innerInlines
"superscript" -> superscript <$> innerInlines
- "inlinemediaobject" -> getImage e
+ "inlinemediaobject" -> getMediaobject e
"quote" -> do
qt <- gets dbQuoteType
let qt' = if qt == SingleQuote then DoubleQuote else SingleQuote
@@ -901,6 +923,7 @@ parseInline (Elem e) =
else doubleQuoted contents
"simplelist" -> simpleList
"segmentedlist" -> segmentedList
+ "classname" -> codeWithLang
"code" -> codeWithLang
"filename" -> codeWithLang
"literal" -> codeWithLang
@@ -920,6 +943,10 @@ parseInline (Elem e) =
"constant" -> codeWithLang
"userinput" -> codeWithLang
"varargs" -> return $ code "(...)"
+ "keycap" -> return (str $ strContent e)
+ "keycombo" -> keycombo <$> (mapM parseInline $ elContent e)
+ "menuchoice" -> menuchoice <$> (mapM parseInline $
+ filter isGuiMenu $ elContent e)
"xref" -> return $ str "?" -- so at least you know something is there
"email" -> return $ link ("mailto:" ++ strContent e) ""
$ str $ strContent e
@@ -959,7 +986,7 @@ parseInline (Elem e) =
let classes' = case attrValue "language" e of
"" -> []
l -> [l]
- return $ codeWith (attrValue "id" e,classes',[]) $ strContent e
+ return $ codeWith (attrValue "id" e,classes',[]) $ strContentRecursive e
simpleList = (mconcat . intersperse (str "," <> space)) <$> mapM getInlines
(filterChildren (named "member") e)
segmentedList = do
@@ -974,3 +1001,10 @@ parseInline (Elem e) =
then mempty
else strong tit <> linebreak
return $ linebreak <> tit' <> segs
+ keycombo = spanWith ("",["keycombo"],[]) .
+ mconcat . intersperse (str "+")
+ menuchoice = spanWith ("",["menuchoice"],[]) .
+ mconcat . intersperse (text " > ")
+ isGuiMenu (Elem x) = named "guimenu" x || named "guisubmenu" x ||
+ named "guimenuitem" x
+ isGuiMenu _ = False
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index 4b5fbfdfc..67a97ae85 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -84,8 +84,7 @@ import Text.Pandoc.Readers.Docx.Lists
import Text.Pandoc.Readers.Docx.Reducible
import Text.Pandoc.Shared
import Text.Pandoc.MediaBag (insertMedia, MediaBag)
-import Data.Maybe (isJust)
-import Data.List (delete, stripPrefix, (\\), intersect, isPrefixOf)
+import Data.List (delete, (\\), intersect)
import Data.Monoid
import Text.TeXMath (writeTeX)
import Data.Default (Default)
@@ -97,14 +96,17 @@ import Control.Applicative ((<$>))
import Data.Sequence (ViewL(..), viewl)
import qualified Data.Sequence as Seq (null)
+import Text.Pandoc.Error
+import Text.Pandoc.Compat.Except
+
readDocx :: ReaderOptions
-> B.ByteString
- -> (Pandoc, MediaBag)
+ -> Either PandocError (Pandoc, MediaBag)
readDocx opts bytes =
case archiveToDocx (toArchive bytes) of
- Right docx -> (Pandoc meta blks, mediaBag) where
- (meta, blks, mediaBag) = (docxToOutput opts docx)
- Left _ -> error $ "couldn't parse docx file"
+ Right docx -> (\(meta, blks, mediaBag) -> (Pandoc meta blks, mediaBag))
+ <$> (docxToOutput opts docx)
+ Left _ -> Left (ParseFailure "couldn't parse docx file")
data DState = DState { docxAnchorMap :: M.Map String String
, docxMediaBag :: MediaBag
@@ -123,10 +125,10 @@ data DEnv = DEnv { docxOptions :: ReaderOptions
instance Default DEnv where
def = DEnv def False
-type DocxContext = ReaderT DEnv (State DState)
+type DocxContext = ExceptT PandocError (ReaderT DEnv (State DState))
-evalDocxContext :: DocxContext a -> DEnv -> DState -> a
-evalDocxContext ctx env st = evalState (runReaderT ctx env) st
+evalDocxContext :: DocxContext a -> DEnv -> DState -> Either PandocError a
+evalDocxContext ctx env st = flip evalState st . flip runReaderT env . runExceptT $ ctx
-- This is empty, but we put it in for future-proofing.
spansToKeep :: [String]
@@ -197,19 +199,9 @@ fixAuthors mv = mv
codeStyles :: [String]
codeStyles = ["VerbatimChar"]
-blockQuoteDivs :: [String]
-blockQuoteDivs = ["Quote", "BlockQuote", "BlockQuotation"]
-
codeDivs :: [String]
codeDivs = ["SourceCode"]
-
--- For the moment, we have English, Danish, German, and French. This
--- is fairly ad-hoc, and there might be a more systematic way to do
--- it, but it's better than nothing.
-headerPrefixes :: [String]
-headerPrefixes = ["Heading", "Overskrift", "berschrift", "Titre"]
-
runElemToInlines :: RunElem -> Inlines
runElemToInlines (TextRun s) = text s
runElemToInlines (LnBrk) = linebreak
@@ -288,7 +280,13 @@ runToInlines :: Run -> DocxContext Inlines
runToInlines (Run rs runElems)
| Just (s, _) <- rStyle rs
, s `elem` codeStyles =
- return $ code $ concatMap runElemToString runElems
+ let rPr = resolveDependentRunStyle rs
+ codeString = code $ concatMap runElemToString runElems
+ in
+ return $ case rVertAlign rPr of
+ Just SupScrpt -> superscript codeString
+ Just SubScrpt -> subscript codeString
+ _ -> codeString
| otherwise = do
let ils = concatReduce (map runElemToInlines runElems)
return $ (runStyleToTransform $ resolveDependentRunStyle rs) ils
@@ -408,7 +406,9 @@ singleParaToPlain blks
singleParaToPlain blks = blks
cellToBlocks :: Cell -> DocxContext Blocks
-cellToBlocks (Cell bps) = concatReduce <$> mapM bodyPartToBlocks bps
+cellToBlocks (Cell bps) = do
+ blks <- concatReduce <$> mapM bodyPartToBlocks bps
+ return $ fromList $ blocksToDefinitions $ blocksToBullets $ toList blks
rowToBlocksList :: Row -> DocxContext [Blocks]
rowToBlocksList (Row cells) = do
@@ -434,9 +434,9 @@ parStyleToTransform pPr
let pPr' = pPr { pStyle = cs, indentation = Nothing}
in
(divWith ("", [c], [])) . (parStyleToTransform pPr')
- | (c:cs) <- pStyle pPr
- , c `elem` blockQuoteDivs =
- let pPr' = pPr { pStyle = cs \\ blockQuoteDivs }
+ | (_:cs) <- pStyle pPr
+ , Just True <- pBlockQuote pPr =
+ let pPr' = pPr { pStyle = cs }
in
blockQuote . (parStyleToTransform pPr')
| (_:cs) <- pStyle pPr =
@@ -467,12 +467,11 @@ bodyPartToBlocks (Paragraph pPr parparts)
$ parStyleToTransform pPr
$ codeBlock
$ concatMap parPartToString parparts
- | (c : cs) <- filter (isJust . isHeaderClass) $ pStyle pPr
- , Just (prefix, n) <- isHeaderClass c = do
+ | Just (style, n) <- pHeading pPr = do
ils <- local (\s-> s{docxInHeaderBlock=True}) $
(concatReduce <$> mapM parPartToInlines parparts)
makeHeaderAnchor $
- headerWith ("", delete (prefix ++ show n) cs, []) n ils
+ headerWith ("", delete style (pStyle pPr), []) n ils
| otherwise = do
ils <- concatReduce <$> mapM parPartToInlines parparts >>=
(return . fromList . trimLineBreaks . normalizeSpaces . toList)
@@ -555,16 +554,7 @@ bodyToOutput (Body bps) = do
blks',
mediaBag)
-docxToOutput :: ReaderOptions -> Docx -> (Meta, [Block], MediaBag)
+docxToOutput :: ReaderOptions -> Docx -> Either PandocError (Meta, [Block], MediaBag)
docxToOutput opts (Docx (Document _ body)) =
let dEnv = def { docxOptions = opts} in
evalDocxContext (bodyToOutput body) dEnv def
-
-isHeaderClass :: String -> Maybe (String, Int)
-isHeaderClass s | (pref:_) <- filter (\h -> isPrefixOf h s) headerPrefixes
- , Just s' <- stripPrefix pref s =
- case reads s' :: [(Int, String)] of
- [] -> Nothing
- ((n, "") : []) -> Just (pref, n)
- _ -> Nothing
-isHeaderClass _ = Nothing
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index 2945a1eda..cce80fb48 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE PatternGuards, ViewPatterns #-}
+{-# LANGUAGE PatternGuards, ViewPatterns, FlexibleInstances #-}
{-
Copyright (C) 2014 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -65,7 +65,8 @@ import Text.Pandoc.Compat.Except
import Text.TeXMath.Readers.OMML (readOMML)
import Text.Pandoc.Readers.Docx.Fonts (getUnicode, Font(..))
import Text.TeXMath (Exp)
-import Data.Char (readLitChar, ord, chr)
+import Text.Pandoc.Readers.Docx.Util
+import Data.Char (readLitChar, ord, chr, isDigit)
data ReaderEnv = ReaderEnv { envNotes :: Notes
, envNumbering :: Numbering
@@ -73,6 +74,7 @@ data ReaderEnv = ReaderEnv { envNotes :: Notes
, envMedia :: Media
, envFont :: Maybe Font
, envCharStyles :: CharStyleMap
+ , envParStyles :: ParStyleMap
}
deriving Show
@@ -107,8 +109,6 @@ mapD f xs =
in
concatMapM handler xs
-type NameSpaces = [(String, String)]
-
data Docx = Docx Document
deriving Show
@@ -122,8 +122,12 @@ type Media = [(FilePath, B.ByteString)]
type CharStyle = (String, RunStyle)
+type ParStyle = (String, ParStyleData)
+
type CharStyleMap = M.Map String RunStyle
+type ParStyleMap = M.Map String ParStyleData
+
data Numbering = Numbering NameSpaces [Numb] [AbstractNumb]
deriving Show
@@ -152,6 +156,9 @@ data ParIndentation = ParIndentation { leftParIndent :: Maybe Integer
data ParagraphStyle = ParagraphStyle { pStyle :: [String]
, indentation :: Maybe ParIndentation
, dropCap :: Bool
+ , pHeading :: Maybe (String, Int)
+ , pNumInfo :: Maybe (String, String)
+ , pBlockQuote :: Maybe Bool
}
deriving Show
@@ -159,6 +166,9 @@ defaultParagraphStyle :: ParagraphStyle
defaultParagraphStyle = ParagraphStyle { pStyle = []
, indentation = Nothing
, dropCap = False
+ , pHeading = Nothing
+ , pNumInfo = Nothing
+ , pBlockQuote = Nothing
}
@@ -213,6 +223,12 @@ data RunStyle = RunStyle { isBold :: Maybe Bool
, rStyle :: Maybe CharStyle}
deriving Show
+data ParStyleData = ParStyleData { headingLev :: Maybe (String, Int)
+ , isBlockQuote :: Maybe Bool
+ , numInfo :: Maybe (String, String)
+ , psStyle :: Maybe ParStyle}
+ deriving Show
+
defaultRunStyle :: RunStyle
defaultRunStyle = RunStyle { isBold = Nothing
, isItalic = Nothing
@@ -232,18 +248,14 @@ type ChangeId = String
type Author = String
type ChangeDate = String
-attrToNSPair :: Attr -> Maybe (String, String)
-attrToNSPair (Attr (QName s _ (Just "xmlns")) val) = Just (s, val)
-attrToNSPair _ = Nothing
-
archiveToDocx :: Archive -> Either DocxError Docx
archiveToDocx archive = do
let notes = archiveToNotes archive
numbering = archiveToNumbering archive
rels = archiveToRelationships archive
media = archiveToMedia archive
- styles = archiveToStyles archive
- rEnv = ReaderEnv notes numbering rels media Nothing styles
+ (styles, parstyles) = archiveToStyles archive
+ rEnv = ReaderEnv notes numbering rels media Nothing styles parstyles
doc <- runD (archiveToDocument archive) rEnv
return $ Docx doc
@@ -252,7 +264,7 @@ archiveToDocument :: Archive -> D Document
archiveToDocument zf = do
entry <- maybeToD $ findEntryByPath "word/document.xml" zf
docElem <- maybeToD $ (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
- let namespaces = mapMaybe attrToNSPair (elAttribs docElem)
+ let namespaces = elemToNameSpaces docElem
bodyElem <- maybeToD $ findChild (elemName namespaces "w" "body") docElem
body <- elemToBody namespaces bodyElem
return $ Document namespaces body
@@ -263,47 +275,69 @@ elemToBody ns element | isElem ns "w" "body" element =
(\bps -> return $ Body bps)
elemToBody _ _ = throwError WrongElem
-archiveToStyles :: Archive -> CharStyleMap
+archiveToStyles :: Archive -> (CharStyleMap, ParStyleMap)
archiveToStyles zf =
let stylesElem = findEntryByPath "word/styles.xml" zf >>=
(parseXMLDoc . UTF8.toStringLazy . fromEntry)
in
case stylesElem of
- Nothing -> M.empty
+ Nothing -> (M.empty, M.empty)
Just styElem ->
- let namespaces = mapMaybe attrToNSPair (elAttribs styElem)
+ let namespaces = elemToNameSpaces styElem
in
- M.fromList $ buildBasedOnList namespaces styElem Nothing
+ ( M.fromList $ buildBasedOnList namespaces styElem
+ (Nothing :: Maybe CharStyle),
+ M.fromList $ buildBasedOnList namespaces styElem
+ (Nothing :: Maybe ParStyle) )
-isBasedOnStyle :: NameSpaces -> Element -> Maybe CharStyle -> Bool
+isBasedOnStyle :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> Bool
isBasedOnStyle ns element parentStyle
| isElem ns "w" "style" element
- , Just "character" <- findAttr (elemName ns "w" "type") element
+ , Just styleType <- findAttr (elemName ns "w" "type") element
+ , styleType == cStyleType parentStyle
, Just basedOnVal <- findChild (elemName ns "w" "basedOn") element >>=
findAttr (elemName ns "w" "val")
- , Just (parentId, _) <- parentStyle = (basedOnVal == parentId)
+ , Just ps <- parentStyle = (basedOnVal == getStyleId ps)
| isElem ns "w" "style" element
- , Just "character" <- findAttr (elemName ns "w" "type") element
+ , Just styleType <- findAttr (elemName ns "w" "type") element
+ , styleType == cStyleType parentStyle
, Nothing <- findChild (elemName ns "w" "basedOn") element
, Nothing <- parentStyle = True
| otherwise = False
-elemToCharStyle :: NameSpaces -> Element -> Maybe CharStyle -> Maybe CharStyle
-elemToCharStyle ns element parentStyle
- | isElem ns "w" "style" element
- , Just "character" <- findAttr (elemName ns "w" "type") element
- , Just styleId <- findAttr (elemName ns "w" "styleId") element =
- Just (styleId, elemToRunStyle ns element parentStyle)
- | otherwise = Nothing
-
-getStyleChildren :: NameSpaces -> Element -> Maybe CharStyle -> [CharStyle]
+class ElemToStyle a where
+ cStyleType :: Maybe a -> String
+ elemToStyle :: NameSpaces -> Element -> Maybe a -> Maybe a
+ getStyleId :: a -> String
+
+instance ElemToStyle CharStyle where
+ cStyleType _ = "character"
+ elemToStyle ns element parentStyle
+ | isElem ns "w" "style" element
+ , Just "character" <- findAttr (elemName ns "w" "type") element
+ , Just styleId <- findAttr (elemName ns "w" "styleId") element =
+ Just (styleId, elemToRunStyle ns element parentStyle)
+ | otherwise = Nothing
+ getStyleId s = fst s
+
+instance ElemToStyle ParStyle where
+ cStyleType _ = "paragraph"
+ elemToStyle ns element parentStyle
+ | isElem ns "w" "style" element
+ , Just "paragraph" <- findAttr (elemName ns "w" "type") element
+ , Just styleId <- findAttr (elemName ns "w" "styleId") element =
+ Just (styleId, elemToParStyleData ns element parentStyle)
+ | otherwise = Nothing
+ getStyleId s = fst s
+
+getStyleChildren :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> [a]
getStyleChildren ns element parentStyle
| isElem ns "w" "styles" element =
- mapMaybe (\e -> elemToCharStyle ns e parentStyle) $
+ mapMaybe (\e -> elemToStyle ns e parentStyle) $
filterChildren (\e' -> isBasedOnStyle ns e' parentStyle) element
| otherwise = []
-buildBasedOnList :: NameSpaces -> Element -> Maybe CharStyle -> [CharStyle]
+buildBasedOnList :: (ElemToStyle a) => NameSpaces -> Element -> Maybe a -> [a]
buildBasedOnList ns element rootStyle =
case (getStyleChildren ns element rootStyle) of
[] -> []
@@ -317,10 +351,10 @@ archiveToNotes zf =
enElem = findEntryByPath "word/endnotes.xml" zf
>>= (parseXMLDoc . UTF8.toStringLazy . fromEntry)
fn_namespaces = case fnElem of
- Just e -> mapMaybe attrToNSPair (elAttribs e)
+ Just e -> elemToNameSpaces e
Nothing -> []
en_namespaces = case enElem of
- Just e -> mapMaybe attrToNSPair (elAttribs e)
+ Just e -> elemToNameSpaces e
Nothing -> []
ns = unionBy (\x y -> fst x == fst y) fn_namespaces en_namespaces
fn = fnElem >>= (elemToNotes ns "footnote")
@@ -420,7 +454,7 @@ archiveToNumbering' zf = do
Nothing -> Just $ Numbering [] [] []
Just entry -> do
numberingElem <- (parseXMLDoc . UTF8.toStringLazy . fromEntry) entry
- let namespaces = mapMaybe attrToNSPair (elAttribs numberingElem)
+ let namespaces = elemToNameSpaces numberingElem
numElems = findChildren
(QName "num" (lookup "w" namespaces) (Just "w"))
numberingElem
@@ -449,15 +483,6 @@ elemToNotes _ _ _ = Nothing
---------------------------------------------
---------------------------------------------
-elemName :: NameSpaces -> String -> String -> QName
-elemName ns prefix name = (QName name (lookup prefix ns) (Just prefix))
-
-isElem :: NameSpaces -> String -> String -> Element -> Bool
-isElem ns prefix name element =
- qName (elName element) == name &&
- qURI (elName element) == (lookup prefix ns)
-
-
elemToTblGrid :: NameSpaces -> Element -> D TblGrid
elemToTblGrid ns element | isElem ns "w" "tblGrid" element =
let cols = findChildren (elemName ns "w" "gridCol") element
@@ -510,20 +535,6 @@ elemToParIndentation ns element | isElem ns "w" "ind" element =
stringToInteger}
elemToParIndentation _ _ = Nothing
-
-elemToNumInfo :: NameSpaces -> Element -> Maybe (String, String)
-elemToNumInfo ns element | isElem ns "w" "p" element = do
- let pPr = findChild (elemName ns "w" "pPr") element
- numPr = pPr >>= findChild (elemName ns "w" "numPr")
- lvl <- numPr >>=
- findChild (elemName ns "w" "ilvl") >>=
- findAttr (elemName ns "w" "val")
- numId <- numPr >>=
- findChild (elemName ns "w" "numId") >>=
- findAttr (elemName ns "w" "val")
- return (numId, lvl)
-elemToNumInfo _ _ = Nothing
-
testBitMask :: String -> Int -> Bool
testBitMask bitMaskS n =
case (reads ("0x" ++ bitMaskS) :: [(Int, String)]) of
@@ -542,18 +553,28 @@ elemToBodyPart ns element
return $ OMathPara expsLst
elemToBodyPart ns element
| isElem ns "w" "p" element
- , Just (numId, lvl) <- elemToNumInfo ns element = do
- let parstyle = elemToParagraphStyle ns element
+ , Just (numId, lvl) <- getNumInfo ns element = do
+ sty <- asks envParStyles
+ let parstyle = elemToParagraphStyle ns element sty
parparts <- mapD (elemToParPart ns) (elChildren element)
num <- asks envNumbering
case lookupLevel numId lvl num of
- Just levelInfo -> return $ ListItem parstyle numId lvl levelInfo parparts
- Nothing -> throwError WrongElem
+ Just levelInfo -> return $ ListItem parstyle numId lvl levelInfo parparts
+ Nothing -> throwError WrongElem
elemToBodyPart ns element
| isElem ns "w" "p" element = do
- let parstyle = elemToParagraphStyle ns element
- parparts <- mapD (elemToParPart ns) (elChildren element)
- return $ Paragraph parstyle parparts
+ sty <- asks envParStyles
+ let parstyle = elemToParagraphStyle ns element sty
+ parparts <- mapD (elemToParPart ns) (elChildren element)
+ case pNumInfo parstyle of
+ Just (numId, lvl) -> do
+ num <- asks envNumbering
+ case lookupLevel numId lvl num of
+ Just levelInfo ->
+ return $ ListItem parstyle numId lvl levelInfo parparts
+ Nothing ->
+ throwError WrongElem
+ Nothing -> return $ Paragraph parstyle parparts
elemToBodyPart ns element
| isElem ns "w" "tbl" element = do
let caption' = findChild (elemName ns "w" "tblPr") element
@@ -601,6 +622,16 @@ elemToParPart ns element
case drawing of
Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp bs)
Nothing -> throwError WrongElem
+-- The below is an attempt to deal with images in deprecated vml format.
+elemToParPart ns element
+ | isElem ns "w" "r" element
+ , Just _ <- findChild (elemName ns "w" "pict") element =
+ let drawing = findElement (elemName ns "v" "imagedata") element
+ >>= findAttr (elemName ns "r" "id")
+ in
+ case drawing of
+ Just s -> expandDrawingId s >>= (\(fp, bs) -> return $ Drawing fp bs)
+ Nothing -> throwError WrongElem
elemToParPart ns element
| isElem ns "w" "r" element =
elemToRun ns element >>= (\r -> return $ PlainRun r)
@@ -625,17 +656,20 @@ elemToParPart ns element
return $ BookMark bmId bmName
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just anchor <- findAttr (elemName ns "w" "anchor") element = do
+ , Just relId <- findAttr (elemName ns "r" "id") element = do
runs <- mapD (elemToRun ns) (elChildren element)
- return $ InternalHyperLink anchor runs
+ rels <- asks envRelationships
+ case lookupRelationship relId rels of
+ Just target -> do
+ case findAttr (elemName ns "w" "anchor") element of
+ Just anchor -> return $ ExternalHyperLink (target ++ '#':anchor) runs
+ Nothing -> return $ ExternalHyperLink target runs
+ Nothing -> return $ ExternalHyperLink "" runs
elemToParPart ns element
| isElem ns "w" "hyperlink" element
- , Just relId <- findAttr (elemName ns "r" "id") element = do
+ , Just anchor <- findAttr (elemName ns "w" "anchor") element = do
runs <- mapD (elemToRun ns) (elChildren element)
- rels <- asks envRelationships
- return $ case lookupRelationship relId rels of
- Just target -> ExternalHyperLink target runs
- Nothing -> ExternalHyperLink "" runs
+ return $ InternalHyperLink anchor runs
elemToParPart ns element
| isElem ns "m" "oMath" element =
(eitherToD $ readOMML $ showElement element) >>= (return . PlainOMath)
@@ -684,14 +718,30 @@ elemToRun ns element
return $ Run runStyle runElems
elemToRun _ _ = throwError WrongElem
-elemToParagraphStyle :: NameSpaces -> Element -> ParagraphStyle
-elemToParagraphStyle ns element
+getParentStyleValue :: (ParStyleData -> Maybe a) -> ParStyleData -> Maybe a
+getParentStyleValue field style
+ | Just value <- field style = Just value
+ | Just parentStyle <- psStyle style
+ = getParentStyleValue field (snd parentStyle)
+getParentStyleValue _ _ = Nothing
+
+getParStyleField :: (ParStyleData -> Maybe a) -> ParStyleMap -> [String] ->
+ Maybe a
+getParStyleField field stylemap styles
+ | x <- mapMaybe (\x -> M.lookup x stylemap) styles
+ , (y:_) <- mapMaybe (getParentStyleValue field) x
+ = Just y
+getParStyleField _ _ _ = Nothing
+
+elemToParagraphStyle :: NameSpaces -> Element -> ParStyleMap -> ParagraphStyle
+elemToParagraphStyle ns element sty
| Just pPr <- findChild (elemName ns "w" "pPr") element =
- ParagraphStyle
- {pStyle =
+ let style =
mapMaybe
(findAttr (elemName ns "w" "val"))
(findChildren (elemName ns "w" "pStyle") pPr)
+ in ParagraphStyle
+ {pStyle = style
, indentation =
findChild (elemName ns "w" "ind") pPr >>=
elemToParIndentation ns
@@ -703,8 +753,11 @@ elemToParagraphStyle ns element
Just "none" -> False
Just _ -> True
Nothing -> False
+ , pHeading = getParStyleField headingLev sty style
+ , pNumInfo = getParStyleField numInfo sty style
+ , pBlockQuote = getParStyleField isBlockQuote sty style
}
-elemToParagraphStyle _ _ = defaultParagraphStyle
+elemToParagraphStyle _ _ _ = defaultParagraphStyle
checkOnOff :: NameSpaces -> Element -> QName -> Maybe Bool
checkOnOff ns rPr tag
@@ -758,6 +811,59 @@ elemToRunStyle ns element parentStyle
}
elemToRunStyle _ _ _ = defaultRunStyle
+isNumericNotNull :: String -> Bool
+isNumericNotNull str = (str /= []) && (all isDigit str)
+
+getHeaderLevel :: NameSpaces -> Element -> Maybe (String,Int)
+getHeaderLevel ns element
+ | Just styleId <- findAttr (elemName ns "w" "styleId") element
+ , Just index <- stripPrefix "Heading" styleId
+ , isNumericNotNull index = Just (styleId, read index)
+ | Just styleId <- findAttr (elemName ns "w" "styleId") element
+ , Just index <- findChild (elemName ns "w" "name") element >>=
+ findAttr (elemName ns "w" "val") >>=
+ stripPrefix "heading "
+ , isNumericNotNull index = Just (styleId, read index)
+getHeaderLevel _ _ = Nothing
+
+blockQuoteStyleIds :: [String]
+blockQuoteStyleIds = ["Quote", "BlockQuote", "BlockQuotation"]
+
+blockQuoteStyleNames :: [String]
+blockQuoteStyleNames = ["Quote", "Block Text"]
+
+getBlockQuote :: NameSpaces -> Element -> Maybe Bool
+getBlockQuote ns element
+ | Just styleId <- findAttr (elemName ns "w" "styleId") element
+ , styleId `elem` blockQuoteStyleIds = Just True
+ | Just styleName <- findChild (elemName ns "w" "name") element >>=
+ findAttr (elemName ns "w" "val")
+ , styleName `elem` blockQuoteStyleNames = Just True
+getBlockQuote _ _ = Nothing
+
+getNumInfo :: NameSpaces -> Element -> Maybe (String, String)
+getNumInfo ns element = do
+ let numPr = findChild (elemName ns "w" "pPr") element >>=
+ findChild (elemName ns "w" "numPr")
+ lvl = fromMaybe "0" (numPr >>=
+ findChild (elemName ns "w" "ilvl") >>=
+ findAttr (elemName ns "w" "val"))
+ numId <- numPr >>=
+ findChild (elemName ns "w" "numId") >>=
+ findAttr (elemName ns "w" "val")
+ return (numId, lvl)
+
+
+elemToParStyleData :: NameSpaces -> Element -> Maybe ParStyle -> ParStyleData
+elemToParStyleData ns element parentStyle =
+ ParStyleData
+ {
+ headingLev = getHeaderLevel ns element
+ , isBlockQuote = getBlockQuote ns element
+ , numInfo = getNumInfo ns element
+ , psStyle = parentStyle
+ }
+
elemToRunElem :: NameSpaces -> Element -> D RunElem
elemToRunElem ns element
| isElem ns "w" "t" element
diff --git a/src/Text/Pandoc/Readers/Docx/StyleMap.hs b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
new file mode 100644
index 000000000..2901ea2a3
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Docx/StyleMap.hs
@@ -0,0 +1,106 @@
+module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
+ , defaultStyleMaps
+ , getStyleMaps
+ , getStyleId
+ , hasStyleName
+ ) where
+
+import Text.XML.Light
+import Text.Pandoc.Readers.Docx.Util
+import Control.Monad.State
+import Data.Char (toLower)
+import qualified Data.Map as M
+
+newtype ParaStyleMap = ParaStyleMap ( M.Map String String )
+newtype CharStyleMap = CharStyleMap ( M.Map String String )
+
+class StyleMap a where
+ alterMap :: (M.Map String String -> M.Map String String) -> a -> a
+ getMap :: a -> M.Map String String
+
+instance StyleMap ParaStyleMap where
+ alterMap f (ParaStyleMap m) = ParaStyleMap $ f m
+ getMap (ParaStyleMap m) = m
+
+instance StyleMap CharStyleMap where
+ alterMap f (CharStyleMap m) = CharStyleMap $ f m
+ getMap (CharStyleMap m) = m
+
+insert :: (StyleMap a) => Maybe String -> Maybe String -> a -> a
+insert (Just k) (Just v) m = alterMap (M.insert k v) m
+insert _ _ m = m
+
+getStyleId :: (StyleMap a) => String -> a -> String
+getStyleId s = M.findWithDefault (filter (/=' ') s) (map toLower s) . getMap
+
+hasStyleName :: (StyleMap a) => String -> a -> Bool
+hasStyleName styleName = M.member (map toLower styleName) . getMap
+
+data StyleMaps = StyleMaps { sNameSpaces :: NameSpaces
+ , sParaStyleMap :: ParaStyleMap
+ , sCharStyleMap :: CharStyleMap
+ }
+
+data StyleType = ParaStyle | CharStyle
+
+defaultStyleMaps :: StyleMaps
+defaultStyleMaps = StyleMaps { sNameSpaces = []
+ , sParaStyleMap = ParaStyleMap M.empty
+ , sCharStyleMap = CharStyleMap M.empty
+ }
+
+type StateM a = State StyleMaps a
+
+getStyleMaps :: Element -> StyleMaps
+getStyleMaps docElem = execState genStyleMap state'
+ where
+ state' = defaultStyleMaps {sNameSpaces = elemToNameSpaces docElem}
+ genStyleItem e = do
+ styleType <- getStyleType e
+ styleId <- getAttrStyleId e
+ nameValLowercase <- fmap (map toLower) `fmap` getNameVal e
+ case styleType of
+ Just ParaStyle -> modParaStyleMap $ insert nameValLowercase styleId
+ Just CharStyle -> modCharStyleMap $ insert nameValLowercase styleId
+ _ -> return ()
+ genStyleMap = do
+ style <- elemName' "style"
+ let styles = findChildren style docElem
+ forM_ styles genStyleItem
+
+modParaStyleMap :: (ParaStyleMap -> ParaStyleMap) -> StateM ()
+modParaStyleMap f = modify $ \s ->
+ s {sParaStyleMap = f $ sParaStyleMap s}
+
+modCharStyleMap :: (CharStyleMap -> CharStyleMap) -> StateM ()
+modCharStyleMap f = modify $ \s ->
+ s {sCharStyleMap = f $ sCharStyleMap s}
+
+getStyleType :: Element -> StateM (Maybe StyleType)
+getStyleType e = do
+ styleTypeStr <- getAttrType e
+ case styleTypeStr of
+ Just "paragraph" -> return $ Just ParaStyle
+ Just "character" -> return $ Just CharStyle
+ _ -> return Nothing
+
+getAttrType :: Element -> StateM (Maybe String)
+getAttrType el = do
+ name <- elemName' "type"
+ return $ findAttr name el
+
+getAttrStyleId :: Element -> StateM (Maybe String)
+getAttrStyleId el = do
+ name <- elemName' "styleId"
+ return $ findAttr name el
+
+getNameVal :: Element -> StateM (Maybe String)
+getNameVal el = do
+ name <- elemName' "name"
+ val <- elemName' "val"
+ return $ findChild name el >>= findAttr val
+
+elemName' :: String -> StateM QName
+elemName' name = do
+ namespaces <- gets sNameSpaces
+ return $ elemName namespaces "w" name
diff --git a/src/Text/Pandoc/Readers/Docx/Util.hs b/src/Text/Pandoc/Readers/Docx/Util.hs
new file mode 100644
index 000000000..891f107b0
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Docx/Util.hs
@@ -0,0 +1,26 @@
+module Text.Pandoc.Readers.Docx.Util (
+ NameSpaces
+ , elemName
+ , isElem
+ , elemToNameSpaces
+ ) where
+
+import Text.XML.Light
+import Data.Maybe (mapMaybe)
+
+type NameSpaces = [(String, String)]
+
+elemToNameSpaces :: Element -> NameSpaces
+elemToNameSpaces = mapMaybe attrToNSPair . elAttribs
+
+attrToNSPair :: Attr -> Maybe (String, String)
+attrToNSPair (Attr (QName s _ (Just "xmlns")) val) = Just (s, val)
+attrToNSPair _ = Nothing
+
+elemName :: NameSpaces -> String -> String -> QName
+elemName ns prefix name = QName name (lookup prefix ns) (Just prefix)
+
+isElem :: NameSpaces -> String -> String -> Element -> Bool
+isElem ns prefix name element =
+ qName (elName element) == name &&
+ qURI (elName element) == lookup prefix ns
diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs
index b061d8683..338540533 100644
--- a/src/Text/Pandoc/Readers/EPUB.hs
+++ b/src/Text/Pandoc/Readers/EPUB.hs
@@ -35,18 +35,20 @@ import Control.DeepSeq.Generics (deepseq, NFData)
import Debug.Trace (trace)
+import Text.Pandoc.Error
+
type Items = M.Map String (FilePath, MimeType)
-readEPUB :: ReaderOptions -> BL.ByteString -> (Pandoc, MediaBag)
+readEPUB :: ReaderOptions -> BL.ByteString -> Either PandocError (Pandoc, MediaBag)
readEPUB opts bytes = runEPUB (archiveToEPUB opts $ toArchive bytes)
-runEPUB :: Except String a -> a
-runEPUB = either error id . runExcept
+runEPUB :: Except PandocError a -> Either PandocError a
+runEPUB = runExcept
-- Note that internal reference are aggresively normalised so that all ids
-- are of the form "filename#id"
--
-archiveToEPUB :: (MonadError String m) => ReaderOptions -> Archive -> m (Pandoc, MediaBag)
+archiveToEPUB :: (MonadError PandocError m) => ReaderOptions -> Archive -> m (Pandoc, MediaBag)
archiveToEPUB os archive = do
-- root is path to folder with manifest file in
(root, content) <- getManifest archive
@@ -64,19 +66,20 @@ archiveToEPUB os archive = do
return $ (ast, mediaBag)
where
os' = os {readerParseRaw = True}
- parseSpineElem :: MonadError String m => FilePath -> (FilePath, MimeType) -> m Pandoc
+ parseSpineElem :: MonadError PandocError m => FilePath -> (FilePath, MimeType) -> m Pandoc
parseSpineElem (normalise -> r) (normalise -> path, mime) = do
when (readerTrace os) (traceM path)
doc <- mimeToReader mime r path
let docSpan = B.doc $ B.para $ B.spanWith (takeFileName path, [], []) mempty
return $ docSpan <> doc
- mimeToReader :: MonadError String m => MimeType -> FilePath -> FilePath -> m Pandoc
+ mimeToReader :: MonadError PandocError m => MimeType -> FilePath -> FilePath -> m Pandoc
mimeToReader "application/xhtml+xml" (normalise -> root) (normalise -> path) = do
fname <- findEntryByPathE (root </> path) archive
- return $ fixInternalReferences path .
+ html <- either throwError return .
readHtml os' .
UTF8.toStringLazy $
fromEntry fname
+ return $ fixInternalReferences path html
mimeToReader s _ path
| s `elem` imageMimes = return $ imageToPandoc path
| otherwise = return $ mempty
@@ -114,7 +117,7 @@ imageMimes = ["image/gif", "image/jpeg", "image/png"]
type CoverImage = FilePath
-parseManifest :: (MonadError String m) => Element -> m (Maybe CoverImage, Items)
+parseManifest :: (MonadError PandocError m) => Element -> m (Maybe CoverImage, Items)
parseManifest content = do
manifest <- findElementE (dfName "manifest") content
let items = findChildren (dfName "item") manifest
@@ -130,7 +133,7 @@ parseManifest content = do
mime <- findAttrE (emptyName "media-type") e
return (uid, (href, mime))
-parseSpine :: MonadError String m => Items -> Element -> m [(FilePath, MimeType)]
+parseSpine :: MonadError PandocError m => Items -> Element -> m [(FilePath, MimeType)]
parseSpine is e = do
spine <- findElementE (dfName "spine") e
let itemRefs = findChildren (dfName "itemref") spine
@@ -141,7 +144,7 @@ parseSpine is e = do
guard linear
findAttr (emptyName "idref") ref
-parseMeta :: MonadError String m => Element -> m Meta
+parseMeta :: MonadError PandocError m => Element -> m Meta
parseMeta content = do
meta <- findElementE (dfName "metadata") content
let dcspace (QName _ (Just "http://purl.org/dc/elements/1.1/") (Just "dc")) = True
@@ -159,7 +162,7 @@ renameMeta :: String -> String
renameMeta "creator" = "author"
renameMeta s = s
-getManifest :: MonadError String m => Archive -> m (String, Element)
+getManifest :: MonadError PandocError m => Archive -> m (String, Element)
getManifest archive = do
metaEntry <- findEntryByPathE ("META-INF" </> "container.xml") archive
docElem <- (parseXMLDocE . UTF8.toStringLazy . fromEntry) metaEntry
@@ -266,18 +269,18 @@ emptyName s = QName s Nothing Nothing
-- Convert Maybe interface to Either
-findAttrE :: MonadError String m => QName -> Element -> m String
+findAttrE :: MonadError PandocError m => QName -> Element -> m String
findAttrE q e = mkE "findAttr" $ findAttr q e
-findEntryByPathE :: MonadError String m => FilePath -> Archive -> m Entry
+findEntryByPathE :: MonadError PandocError m => FilePath -> Archive -> m Entry
findEntryByPathE (normalise -> path) a =
mkE ("No entry on path: " ++ path) $ findEntryByPath path a
-parseXMLDocE :: MonadError String m => String -> m Element
+parseXMLDocE :: MonadError PandocError m => String -> m Element
parseXMLDocE doc = mkE "Unable to parse XML doc" $ parseXMLDoc doc
-findElementE :: MonadError String m => QName -> Element -> m Element
+findElementE :: MonadError PandocError m => QName -> Element -> m Element
findElementE e x = mkE ("Unable to find element: " ++ show e) $ findElement e x
-mkE :: MonadError String m => String -> Maybe a -> m a
-mkE s = maybe (throwError s) return
+mkE :: MonadError PandocError m => String -> Maybe a -> m a
+mkE s = maybe (throwError . ParseFailure $ s) return
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index 4e0bb375a..fcba16e04 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -1,6 +1,7 @@
-{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,
+ViewPatterns#-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.HTML
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -43,14 +44,14 @@ import Text.Pandoc.Definition
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Builder (Blocks, Inlines, trimInlines, HasMeta(..))
import Text.Pandoc.Shared ( extractSpaces, renderTags'
- , escapeURI, safeRead )
+ , escapeURI, safeRead, mapLeft )
import Text.Pandoc.Options (ReaderOptions(readerParseRaw, readerTrace)
, Extension (Ext_epub_html_exts,
Ext_native_divs, Ext_native_spans))
import Text.Pandoc.Parsing hiding ((<|>))
import Text.Pandoc.Walk
import Data.Maybe ( fromMaybe, isJust)
-import Data.List ( intercalate, isInfixOf )
+import Data.List ( intercalate, isInfixOf, isPrefixOf, isSuffixOf )
import Data.Char ( isDigit )
import Control.Monad ( liftM, guard, when, mzero, void, unless )
import Control.Arrow ((***))
@@ -61,16 +62,20 @@ import Debug.Trace (trace)
import Text.TeXMath (readMathML, writeTeX)
import Data.Default (Default (..), def)
import Control.Monad.Reader (Reader,ask, asks, local, runReader)
+import Network.URI (isURI)
+import Text.Pandoc.Error
+
+import Text.Parsec.Error
-- | Convert HTML-formatted string to 'Pandoc' document.
readHtml :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assumes @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readHtml opts inp =
- case flip runReader def $ runParserT parseDoc (HTMLState def{ stateOptions = opts } []) "source" tags of
- Left err' -> error $ "\nError at " ++ show err'
- Right result -> result
+ mapLeft (ParseFailure . getError) . flip runReader def $
+ runParserT parseDoc (HTMLState def{ stateOptions = opts } [] Nothing)
+ "source" tags
where tags = stripPrefixes . canonicalizeTags $
parseTagsOptions parseOptions{ optTagPosition = True } inp
parseDoc = do
@@ -78,6 +83,9 @@ readHtml opts inp =
meta <- stateMeta . parserState <$> getState
bs' <- replaceNotes (B.toList blocks)
return $ Pandoc meta bs'
+ getError (errorMessages -> ms) = case ms of
+ [] -> ""
+ (m:_) -> messageString m
replaceNotes :: [Block] -> TagParser [Block]
replaceNotes = walkM replaceNotes'
@@ -91,7 +99,8 @@ replaceNotes' x = return x
data HTMLState =
HTMLState
{ parserState :: ParserState,
- noteTable :: [(String, Blocks)]
+ noteTable :: [(String, Blocks)],
+ baseHref :: Maybe String
}
data HTMLLocal = HTMLLocal { quoteContext :: QuoteContext
@@ -113,7 +122,7 @@ pBody :: TagParser Blocks
pBody = pInTags "body" block
pHead :: TagParser Blocks
-pHead = pInTags "head" $ pTitle <|> pMetaTag <|> (mempty <$ pAnyTag)
+pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag)
where pTitle = pInTags "title" inline >>= setTitle . trimInlines
setTitle t = mempty <$ (updateState $ B.setMeta "title" t)
pMetaTag = do
@@ -125,6 +134,17 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> (mempty <$ pAnyTag)
let content = fromAttrib "content" mt
updateState $ B.setMeta name (B.text content)
return mempty
+ pBaseTag = do
+ bt <- pSatisfy (~== TagOpen "base" [])
+ let baseH = fromAttrib "href" bt
+ if null baseH
+ then return mempty
+ else do
+ let baseH' = case reverse baseH of
+ '/':_ -> baseH
+ _ -> baseH ++ "/"
+ updateState $ \st -> st{ baseHref = Just baseH' }
+ return mempty
block :: TagParser Blocks
block = do
@@ -250,7 +270,14 @@ pOrderedList = try $ do
"lower-alpha" -> LowerAlpha
"upper-alpha" -> UpperAlpha
"decimal" -> Decimal
- _ -> DefaultStyle
+ _ ->
+ case lookup "type" attribs of
+ Just "1" -> Decimal
+ Just "I" -> UpperRoman
+ Just "i" -> LowerRoman
+ Just "A" -> UpperAlpha
+ Just "a" -> LowerAlpha
+ _ -> DefaultStyle
let nonItem = pSatisfy (\t ->
not (tagOpen (`elem` ["li","ol","ul","dl"]) (const True) t) &&
not (t ~== TagClose "ol"))
@@ -373,13 +400,21 @@ pTable = try $ do
skipMany pBlank
caption <- option mempty $ pInTags "caption" inline <* skipMany pBlank
-- TODO actually read these and take width information from them
- widths' <- pColgroup <|> many pCol
- head' <- option [] $ pOptInTag "thead" $ pInTags "tr" (pCell "th")
- skipMany pBlank
- rows <- pOptInTag "tbody"
- $ many1 $ try $ skipMany pBlank >> pInTags "tr" (pCell "td")
- skipMany pBlank
+ widths' <- (mconcat <$> many1 pColgroup) <|> many pCol
+ let pTh = option [] $ pInTags "tr" (pCell "th")
+ pTr = try $ skipMany pBlank >> pInTags "tr" (pCell "td" <|> pCell "th")
+ pTBody = do pOptInTag "tbody" $ many1 pTr
+ head'' <- pOptInTag "thead" pTh
+ head' <- pOptInTag "tbody" $ do
+ if null head''
+ then pTh
+ else return head''
+ rowsLs <- many pTBody
+ rows' <- pOptInTag "tfoot" $ many pTr
TagClose _ <- pSatisfy (~== TagClose "table")
+ let rows = (concat rowsLs) ++ rows'
+ -- fail on empty table
+ guard $ not $ null head' && null rows
let isSinglePlain x = case B.toList x of
[Plain _] -> True
_ -> False
@@ -551,7 +586,11 @@ pAnchor = try $ do
pRelLink :: TagParser Inlines
pRelLink = try $ do
tag <- pSatisfy (tagOpenLit "a" (isJust . lookup "href"))
- let url = fromAttrib "href" tag
+ mbBaseHref <- baseHref <$> getState
+ let url' = fromAttrib "href" tag
+ let url = case (isURI url', mbBaseHref) of
+ (False, Just h) -> h ++ url'
+ _ -> url'
let title = fromAttrib "title" tag
let uid = fromAttrib "id" tag
let spanC = case uid of
@@ -563,7 +602,11 @@ pRelLink = try $ do
pImage :: TagParser Inlines
pImage = do
tag <- pSelfClosing (=="img") (isJust . lookup "src")
- let url = fromAttrib "src" tag
+ mbBaseHref <- baseHref <$> getState
+ let url' = fromAttrib "src" tag
+ let url = case (isURI url', mbBaseHref) of
+ (False, Just h) -> h ++ url'
+ _ -> url'
let title = fromAttrib "title" tag
let alt = fromAttrib "alt" tag
return $ B.image (escapeURI url) title (B.text alt)
@@ -624,14 +667,17 @@ pInTags tagtype parser = try $ do
pSatisfy (~== TagOpen tagtype [])
mconcat <$> manyTill parser (pCloses tagtype <|> eof)
-pOptInTag :: String -> TagParser a
- -> TagParser a
-pOptInTag tagtype parser = try $ do
- open <- option False (pSatisfy (~== TagOpen tagtype []) >> return True)
+-- parses p, preceeded by an optional opening tag
+-- and followed by an optional closing tags
+pOptInTag :: String -> TagParser a -> TagParser a
+pOptInTag tagtype p = try $ do
+ skipMany pBlank
+ optional $ pSatisfy (~== TagOpen tagtype [])
+ skipMany pBlank
+ x <- p
skipMany pBlank
- x <- parser
+ optional $ pSatisfy (~== TagClose tagtype)
skipMany pBlank
- when open $ pCloses tagtype
return x
pCloses :: String -> TagParser ()
@@ -740,7 +786,7 @@ pSpace = many1 (satisfy isSpace) >> return B.space
--
eitherBlockOrInline :: [String]
-eitherBlockOrInline = ["audio", "applet", "button", "iframe",
+eitherBlockOrInline = ["audio", "applet", "button", "iframe", "embed",
"del", "ins",
"progress", "map", "area", "noscript", "script",
"object", "svg", "video", "source"]
@@ -758,7 +804,7 @@ blockHtmlTags :: [String]
blockHtmlTags = ["?xml", "!DOCTYPE", "address", "article", "aside",
"blockquote", "body", "button", "canvas",
"caption", "center", "col", "colgroup", "dd", "dir", "div",
- "dl", "dt", "embed", "fieldset", "figcaption", "figure",
+ "dl", "dt", "fieldset", "figcaption", "figure",
"footer", "form", "h1", "h2", "h3", "h4",
"h5", "h6", "head", "header", "hgroup", "hr", "html",
"isindex", "menu", "noframes", "ol", "output", "p", "pre",
@@ -815,6 +861,7 @@ isCommentTag = tagComment (const True)
closes :: String -> String -> Bool
_ `closes` "body" = False
_ `closes` "html" = False
+"body" `closes` "head" = True
"a" `closes` "a" = True
"li" `closes` "li" = True
"th" `closes` t | t `elem` ["th","td"] = True
@@ -856,7 +903,7 @@ htmlInBalanced :: (Monad m)
-> ParserT String st m String
htmlInBalanced f = try $ do
(TagOpen t _, tag) <- htmlTag f
- guard $ '/' `notElem` tag -- not a self-closing tag
+ guard $ not $ "/>" `isSuffixOf` tag -- not a self-closing tag
let stopper = htmlTag (~== TagClose t)
let anytag = snd <$> htmlTag (const True)
contents <- many $ notFollowedBy' stopper >>
@@ -869,17 +916,26 @@ htmlTag :: Monad m
=> (Tag String -> Bool)
-> ParserT [Char] st m (Tag String, String)
htmlTag f = try $ do
- lookAhead $ char '<' >> (oneOf "/!?" <|> letter)
- (next : _) <- getInput >>= return . canonicalizeTags . parseTags
+ lookAhead (char '<')
+ inp <- getInput
+ let hasTagWarning (TagWarning _:_) = True
+ hasTagWarning _ = False
+ let (next : rest) = canonicalizeTags $ parseTagsOptions
+ parseOptions{ optTagWarning = True } inp
guard $ f next
- -- advance the parser
case next of
- TagComment s -> do
+ TagComment s
+ | "<!--" `isPrefixOf` inp -> do
count (length s + 4) anyChar
skipMany (satisfy (/='>'))
char '>'
return (next, "<!--" ++ s ++ "-->")
+ | otherwise -> fail "bogus comment mode, HTML5 parse error"
_ -> do
+ -- we get a TagWarning on things like
+ -- <www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>
+ -- which should NOT be parsed as an HTML tag, see #2277
+ guard $ not $ hasTagWarning rest
rendered <- manyTill anyChar (char '>')
return (next, rendered ++ ">")
@@ -925,7 +981,7 @@ instance HasReaderOptions HTMLState where
extractReaderOptions = extractReaderOptions . parserState
instance Default HTMLState where
- def = HTMLState def []
+ def = HTMLState def [] Nothing
instance HasMeta HTMLState where
setMeta s b st = st {parserState = setMeta s b $ parserState st}
diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs
index 4b46c869d..aa2534afc 100644
--- a/src/Text/Pandoc/Readers/Haddock.hs
+++ b/src/Text/Pandoc/Readers/Haddock.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
{- |
Module : Text.Pandoc.Readers.Haddock
Copyright : Copyright (C) 2013 David Lazar
@@ -25,11 +26,18 @@ import Documentation.Haddock.Parser
import Documentation.Haddock.Types
import Debug.Trace (trace)
+import Text.Pandoc.Error
+
-- | Parse Haddock markup and return a 'Pandoc' document.
readHaddock :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse
- -> Pandoc
-readHaddock opts = B.doc . docHToBlocks . trace' . parseParas
+ -> Either PandocError Pandoc
+readHaddock opts =
+#if MIN_VERSION_haddock_library(1,2,0)
+ Right . B.doc . docHToBlocks . trace' . _doc . parseParas
+#else
+ Right . B.doc . docHToBlocks . trace' . parseParas
+#endif
where trace' x = if readerTrace opts
then trace (show x) x
else x
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index 9f51e9a8f..0da912ea6 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables, OverloadedStrings #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.LaTeX
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -42,26 +42,25 @@ import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding ((<|>), many, optional, space,
mathDisplay, mathInline)
import qualified Text.Pandoc.UTF8 as UTF8
-import Data.Char ( chr, ord )
+import Data.Char ( chr, ord, isLetter, isAlphaNum )
import Control.Monad.Trans (lift)
import Control.Monad
import Text.Pandoc.Builder
-import Data.Char (isLetter, isAlphaNum)
import Control.Applicative
import Data.Monoid
-import Data.Maybe (fromMaybe)
+import Data.Maybe (fromMaybe, maybeToList)
import System.Environment (getEnv)
-import System.FilePath (replaceExtension, (</>))
-import Data.List (intercalate, intersperse)
+import System.FilePath (replaceExtension, (</>), takeExtension, addExtension)
+import Data.List (intercalate)
import qualified Data.Map as M
import qualified Control.Exception as E
-import System.FilePath (takeExtension, addExtension)
import Text.Pandoc.Highlighting (fromListingsLanguage)
+import Text.Pandoc.Error
-- | Parse LaTeX from string and return 'Pandoc' document.
readLaTeX :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assumes @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readLaTeX opts = readWith parseLaTeX def{ stateOptions = opts }
parseLaTeX :: LP Pandoc
@@ -73,17 +72,16 @@ parseLaTeX = do
let (Pandoc _ bs') = doc bs
return $ Pandoc meta bs'
-type LP = Parser [Char] ParserState
+type LP = Parser String ParserState
anyControlSeq :: LP String
anyControlSeq = do
char '\\'
next <- option '\n' anyChar
- name <- case next of
- '\n' -> return ""
- c | isLetter c -> (c:) <$> (many letter <* optional sp)
- | otherwise -> return [c]
- return name
+ case next of
+ '\n' -> return ""
+ c | isLetter c -> (c:) <$> (many letter <* optional sp)
+ | otherwise -> return [c]
controlSeq :: String -> LP String
controlSeq name = try $ do
@@ -103,7 +101,7 @@ dimenarg = try $ do
sp :: LP ()
sp = skipMany1 $ satisfy (\c -> c == ' ' || c == '\t')
- <|> (try $ newline <* lookAhead anyChar <* notFollowedBy blankline)
+ <|> try (newline <* lookAhead anyChar <* notFollowedBy blankline)
isLowerHex :: Char -> Bool
isLowerHex x = x >= '0' && x <= '9' || x >= 'a' && x <= 'f'
@@ -161,50 +159,47 @@ mathInline :: LP String -> LP Inlines
mathInline p = math <$> (try p >>= applyMacros')
mathChars :: LP String
-mathChars = concat <$>
- many ( many1 (satisfy (\c -> c /= '$' && c /='\\'))
- <|> (\c -> ['\\',c]) <$> (try $ char '\\' *> anyChar)
- )
+mathChars = (concat <$>) $
+ many $
+ many1 (satisfy (\c -> c /= '$' && c /='\\'))
+ <|> (\c -> ['\\',c]) <$> try (char '\\' *> anyChar)
quoted' :: (Inlines -> Inlines) -> LP String -> LP () -> LP Inlines
quoted' f starter ender = do
startchs <- starter
try ((f . mconcat) <$> manyTill inline ender) <|> lit startchs
-double_quote :: LP Inlines
-double_quote =
- ( quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
+doubleQuote :: LP Inlines
+doubleQuote =
+ quoted' doubleQuoted (try $ string "``") (void $ try $ string "''")
<|> quoted' doubleQuoted (string "“") (void $ char '”')
-- the following is used by babel for localized quotes:
<|> quoted' doubleQuoted (try $ string "\"`") (void $ try $ string "\"'")
<|> quoted' doubleQuoted (string "\"") (void $ char '"')
- )
-single_quote :: LP Inlines
-single_quote =
- ( quoted' singleQuoted (string "`") (try $ char '\'' >> notFollowedBy letter)
+singleQuote :: LP Inlines
+singleQuote =
+ quoted' singleQuoted (string "`") (try $ char '\'' >> notFollowedBy letter)
<|> quoted' singleQuoted (string "‘") (try $ char '’' >> notFollowedBy letter)
- )
inline :: LP Inlines
inline = (mempty <$ comment)
<|> (space <$ sp)
<|> inlineText
<|> inlineCommand
+ <|> inlineEnvironment
<|> inlineGroup
<|> (char '-' *> option (str "-")
- ((char '-') *> option (str "–") (str "—" <$ char '-')))
- <|> double_quote
- <|> single_quote
+ (char '-' *> option (str "–") (str "—" <$ char '-')))
+ <|> doubleQuote
+ <|> singleQuote
<|> (str "”" <$ try (string "''"))
<|> (str "”" <$ char '”')
<|> (str "’" <$ char '\'')
<|> (str "’" <$ char '’')
<|> (str "\160" <$ char '~')
- <|> (mathDisplay $ string "$$" *> mathChars <* string "$$")
- <|> (mathInline $ char '$' *> mathChars <* char '$')
- <|> (superscript <$> (char '^' *> tok))
- <|> (subscript <$> (char '_' *> tok))
+ <|> mathDisplay (string "$$" *> mathChars <* string "$$")
+ <|> mathInline (char '$' *> mathChars <* char '$')
<|> (guardEnabled Ext_literate_haskell *> char '|' *> doLHSverb)
<|> (str . (:[]) <$> tildeEscape)
<|> (str . (:[]) <$> oneOf "[]")
@@ -237,20 +232,32 @@ block = (mempty <$ comment)
blocks :: LP Blocks
blocks = mconcat <$> many block
+getRawCommand :: String -> LP String
+getRawCommand name' = do
+ rawargs <- withRaw (skipopts *> option "" dimenarg *> many braced)
+ return $ '\\' : name' ++ snd rawargs
+
+lookupListDefault :: (Ord k) => v -> [k] -> M.Map k v -> v
+lookupListDefault d = (fromMaybe d .) . lookupList
+ where
+ lookupList l m = msum $ map (`M.lookup` m) l
+
blockCommand :: LP Blocks
blockCommand = try $ do
name <- anyControlSeq
guard $ name /= "begin" && name /= "end"
star <- option "" (string "*" <* optional sp)
let name' = name ++ star
- case M.lookup name' blockCommands of
- Just p -> p
- Nothing -> case M.lookup name blockCommands of
- Just p -> p
- Nothing -> mzero
+ let raw = do
+ rawcommand <- getRawCommand name'
+ transformed <- applyMacros' rawcommand
+ guard $ transformed /= rawcommand
+ notFollowedBy $ parseFromString inlines transformed
+ parseFromString blocks transformed
+ lookupListDefault raw [name',name] blockCommands
inBrackets :: Inlines -> Inlines
-inBrackets x = (str "[") <> x <> (str "]")
+inBrackets x = str "[" <> x <> str "]"
-- eat an optional argument and one or more arguments in braces
ignoreInlines :: String -> (String, LP Inlines)
@@ -258,19 +265,21 @@ ignoreInlines name = (name, doraw <|> (mempty <$ optargs))
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
contseq = '\\':name
doraw = (rawInline "latex" . (contseq ++) . snd) <$>
- (getOption readerParseRaw >>= guard >> (withRaw optargs))
+ (getOption readerParseRaw >>= guard >> withRaw optargs)
ignoreBlocks :: String -> (String, LP Blocks)
ignoreBlocks name = (name, doraw <|> (mempty <$ optargs))
where optargs = skipopts *> skipMany (try $ optional sp *> braced)
contseq = '\\':name
doraw = (rawBlock "latex" . (contseq ++) . snd) <$>
- (getOption readerParseRaw >>= guard >> (withRaw optargs))
+ (getOption readerParseRaw >>= guard >> withRaw optargs)
blockCommands :: M.Map String (LP Blocks)
blockCommands = M.fromList $
[ ("par", mempty <$ skipopts)
- , ("title", mempty <$ (skipopts *> tok >>= addMeta "title"))
+ , ("title", mempty <$ (skipopts *>
+ (grouped inline >>= addMeta "title")
+ <|> (grouped block >>= addMeta "title")))
, ("subtitle", mempty <$ (skipopts *> tok >>= addMeta "subtitle"))
, ("author", mempty <$ (skipopts *> authors))
-- -- in letter class, temp. store address & sig as title, author
@@ -301,10 +310,10 @@ blockCommands = M.fromList $
--
, ("hrule", pure horizontalRule)
, ("rule", skipopts *> tok *> tok *> pure horizontalRule)
- , ("item", skipopts *> loose_item)
+ , ("item", skipopts *> looseItem)
, ("documentclass", skipopts *> braced *> preamble)
, ("centerline", (para . trimInlines) <$> (skipopts *> tok))
- , ("caption", skipopts *> tok >>= setCaption)
+ , ("caption", skipopts *> setCaption)
, ("PandocStartInclude", startInclude)
, ("PandocEndInclude", endInclude)
, ("bibliography", mempty <$ (skipopts *> braced >>=
@@ -327,6 +336,7 @@ blockCommands = M.fromList $
, "hyperdef"
, "markboth", "markright", "markleft"
, "hspace", "vspace"
+ , "newpage"
]
addMeta :: ToMetaValue a => String -> a -> LP ()
@@ -336,9 +346,16 @@ addMeta field val = updateState $ \st ->
splitBibs :: String -> [Inlines]
splitBibs = map (str . flip replaceExtension "bib" . trim) . splitBy (==',')
-setCaption :: Inlines -> LP Blocks
-setCaption ils = do
- updateState $ \st -> st{ stateCaption = Just ils }
+setCaption :: LP Blocks
+setCaption = do
+ ils <- tok
+ mblabel <- option Nothing $
+ try $ spaces' >> controlSeq "label" >> (Just <$> tok)
+ let ils' = case mblabel of
+ Just lab -> ils <> spanWith
+ ("",[],[("data-label", stringify lab)]) mempty
+ Nothing -> ils
+ updateState $ \st -> st{ stateCaption = Just ils' }
return mempty
resetCaption :: LP ()
@@ -361,7 +378,7 @@ section (ident, classes, kvs) lvl = do
let lvl' = if hasChapters then lvl + 1 else lvl
skipopts
contents <- grouped inline
- lab <- option ident $ try (spaces >> controlSeq "label" >> spaces >> braced)
+ lab <- option ident $ try (spaces' >> controlSeq "label" >> spaces' >> braced)
attr' <- registerHeader (lab, classes, kvs) contents
return $ headerWith attr' lvl' contents
@@ -374,25 +391,39 @@ inlineCommand = try $ do
star <- option "" (string "*")
let name' = name ++ star
let raw = do
- rawargs <- withRaw (skipopts *> option "" dimenarg *> many braced)
- let rawcommand = '\\' : name ++ star ++ snd rawargs
+ rawcommand <- getRawCommand name'
transformed <- applyMacros' rawcommand
if transformed /= rawcommand
then parseFromString inlines transformed
else if parseRaw
then return $ rawInline "latex" rawcommand
else return mempty
- case M.lookup name' inlineCommands of
- Just p -> p <|> raw
- Nothing -> case M.lookup name inlineCommands of
- Just p -> p <|> raw
- Nothing -> raw
+ lookupListDefault mzero [name',name] inlineCommands
+ <|> raw
unlessParseRaw :: LP ()
unlessParseRaw = getOption readerParseRaw >>= guard . not
isBlockCommand :: String -> Bool
-isBlockCommand s = maybe False (const True) $ M.lookup s blockCommands
+isBlockCommand s = s `M.member` blockCommands
+
+
+inlineEnvironments :: M.Map String (LP Inlines)
+inlineEnvironments = M.fromList
+ [ ("displaymath", mathEnv id Nothing "displaymath")
+ , ("equation", mathEnv id Nothing "equation")
+ , ("equation*", mathEnv id Nothing "equation*")
+ , ("gather", mathEnv id (Just "gathered") "gather")
+ , ("gather*", mathEnv id (Just "gathered") "gather*")
+ , ("multline", mathEnv id (Just "gathered") "multline")
+ , ("multline*", mathEnv id (Just "gathered") "multline*")
+ , ("eqnarray", mathEnv id (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnv id (Just "aligned") "eqnarray*")
+ , ("align", mathEnv id (Just "aligned") "align")
+ , ("align*", mathEnv id (Just "aligned") "align*")
+ , ("alignat", mathEnv id (Just "aligned") "alignat")
+ , ("alignat*", mathEnv id (Just "aligned") "alignat*")
+ ]
inlineCommands :: M.Map String (LP Inlines)
inlineCommands = M.fromList $
@@ -414,9 +445,14 @@ inlineCommands = M.fromList $
, ("sim", lit "~")
, ("label", unlessParseRaw >> (inBrackets <$> tok))
, ("ref", unlessParseRaw >> (inBrackets <$> tok))
+ , ("noindent", unlessParseRaw >> return mempty)
+ , ("textgreek", tok)
+ , ("sep", lit ",")
+ , ("cref", unlessParseRaw >> (inBrackets <$> tok)) -- from cleveref.sty
, ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
, ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
- , ("ensuremath", mathInline $ braced)
+ , ("ensuremath", mathInline braced)
+ , ("texorpdfstring", (\_ x -> x) <$> tok <*> tok)
, ("P", lit "¶")
, ("S", lit "§")
, ("$", lit "$")
@@ -464,7 +500,7 @@ inlineCommands = M.fromList $
, ("v", option (str "v") $ try $ tok >>= accent hacek)
, ("u", option (str "u") $ try $ tok >>= accent breve)
, ("i", lit "i")
- , ("\\", linebreak <$ (optional (bracketed inline) *> optional sp))
+ , ("\\", linebreak <$ (optional (bracketed inline) *> spaces'))
, (",", pure mempty)
, ("@", pure mempty)
, (" ", lit "\160")
@@ -477,7 +513,7 @@ inlineCommands = M.fromList $
, ("thanks", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
, ("footnote", (note . mconcat) <$> (char '{' *> manyTill block (char '}')))
, ("verb", doverb)
- , ("lstinline", doverb)
+ , ("lstinline", skipopts *> doverb)
, ("Verb", doverb)
, ("texttt", (code . stringify . toList) <$> tok)
, ("url", (unescapeURL <$> braced) >>= \url ->
@@ -494,6 +530,7 @@ inlineCommands = M.fromList $
, ("citealp", citation "citealp" NormalCitation False)
, ("citealp*", citation "citealp*" NormalCitation False)
, ("autocite", citation "autocite" NormalCitation False)
+ , ("smartcite", citation "smartcite" NormalCitation False)
, ("footcite", inNote <$> citation "footcite" NormalCitation False)
, ("parencite", citation "parencite" NormalCitation False)
, ("supercite", citation "supercite" NormalCitation False)
@@ -516,6 +553,7 @@ inlineCommands = M.fromList $
, ("supercites", citation "supercites" NormalCitation True)
, ("footcitetexts", inNote <$> citation "footcitetexts" NormalCitation True)
, ("Autocite", citation "Autocite" NormalCitation False)
+ , ("Smartcite", citation "Smartcite" NormalCitation False)
, ("Footcite", citation "Footcite" NormalCitation False)
, ("Parencite", citation "Parencite" NormalCitation False)
, ("Supercite", citation "Supercite" NormalCitation False)
@@ -542,7 +580,7 @@ inlineCommands = M.fromList $
] ++ map ignoreInlines
-- these commands will be ignored unless --parse-raw is specified,
-- in which case they will appear as raw latex blocks:
- [ "noindent", "index" ]
+ [ "index" ]
mkImage :: String -> LP Inlines
mkImage src = do
@@ -559,7 +597,7 @@ inNote ils =
unescapeURL :: String -> String
unescapeURL ('\\':x:xs) | isEscapable x = x:unescapeURL xs
- where isEscapable c = c `elem` "#$%&~_^\\{}"
+ where isEscapable c = c `elem` ("#$%&~_^\\{}" :: String)
unescapeURL (x:xs) = x:unescapeURL xs
unescapeURL [] = ""
@@ -585,7 +623,7 @@ lit = pure . str
accent :: (Char -> String) -> Inlines -> LP Inlines
accent f ils =
case toList ils of
- (Str (x:xs) : ys) -> return $ fromList $ (Str (f x ++ xs) : ys)
+ (Str (x:xs) : ys) -> return $ fromList (Str (f x ++ xs) : ys)
[] -> mzero
_ -> return ils
@@ -774,7 +812,7 @@ breve 'u' = "ŭ"
breve c = [c]
tok :: LP Inlines
-tok = try $ grouped inline <|> inlineCommand <|> str <$> (count 1 $ inlineChar)
+tok = try $ grouped inline <|> inlineCommand <|> str <$> count 1 inlineChar
opt :: LP Inlines
opt = bracketed inline <* optional sp
@@ -786,15 +824,20 @@ inlineText :: LP Inlines
inlineText = str <$> many1 inlineChar
inlineChar :: LP Char
-inlineChar = noneOf "\\$%^_&~#{}^'`\"‘’“”-[] \t\n"
+inlineChar = noneOf "\\$%&~#{}^'`\"‘’“”-[] \t\n"
environment :: LP Blocks
environment = do
controlSeq "begin"
name <- braced
- case M.lookup name environments of
- Just p -> p <|> rawEnv name
- Nothing -> rawEnv name
+ M.findWithDefault mzero name environments
+ <|> rawEnv name
+
+inlineEnvironment :: LP Inlines
+inlineEnvironment = try $ do
+ controlSeq "begin"
+ name <- braced
+ M.findWithDefault mzero name inlineEnvironments
rawEnv :: String -> LP Blocks
rawEnv name = do
@@ -807,15 +850,11 @@ rawEnv name = do
----
-type IncludeParser = ParserT [Char] [String] IO String
+type IncludeParser = ParserT String [String] IO String
-- | Replace "include" commands with file contents.
-handleIncludes :: String -> IO String
-handleIncludes s = do
- res <- runParserT includeParser' [] "input" s
- case res of
- Right s' -> return s'
- Left e -> error $ show e
+handleIncludes :: String -> IO (Either PandocError String)
+handleIncludes s = mapLeft (ParsecError s) <$> runParserT includeParser' [] "input" s
includeParser' :: IncludeParser
includeParser' =
@@ -857,6 +896,12 @@ backslash' = string "\\"
braced' :: IncludeParser
braced' = try $ char '{' *> manyTill (satisfy (/='}')) (char '}')
+maybeAddExtension :: String -> FilePath -> FilePath
+maybeAddExtension ext fp =
+ if null (takeExtension fp)
+ then addExtension fp ext
+ else fp
+
include' :: IncludeParser
include' = do
fs' <- try $ do
@@ -865,11 +910,11 @@ include' = do
<|> try (string "input")
<|> string "usepackage"
-- skip options
- skipMany $ try $ char '[' *> (manyTill anyChar (char ']'))
+ skipMany $ try $ char '[' *> manyTill anyChar (char ']')
fs <- (map trim . splitBy (==',')) <$> braced'
return $ if name == "usepackage"
- then map (flip replaceExtension ".sty") fs
- else map (flip replaceExtension ".tex") fs
+ then map (maybeAddExtension ".sty") fs
+ else map (maybeAddExtension ".tex") fs
pos <- getPosition
containers <- getState
let fn = case containers of
@@ -938,14 +983,14 @@ keyvals = try $ char '[' *> manyTill keyval (char ']')
alltt :: String -> LP Blocks
alltt t = walk strToCode <$> parseFromString blocks
(substitute " " "\\ " $ substitute "%" "\\%" $
- concat $ intersperse "\\\\\n" $ lines t)
+ intercalate "\\\\\n" $ lines t)
where strToCode (Str s) = Code nullAttr s
strToCode x = x
-rawLaTeXBlock :: Parser [Char] ParserState String
+rawLaTeXBlock :: LP String
rawLaTeXBlock = snd <$> try (withRaw (environment <|> blockCommand))
-rawLaTeXInline :: Parser [Char] ParserState Inline
+rawLaTeXInline :: LP Inline
rawLaTeXInline = do
raw <- (snd <$> withRaw inlineCommand) <|> (snd <$> withRaw blockCommand)
RawInline "latex" <$> applyMacros' raw
@@ -954,41 +999,43 @@ addImageCaption :: Blocks -> LP Blocks
addImageCaption = walkM go
where go (Image alt (src,tit)) = do
mbcapt <- stateCaption <$> getState
- case mbcapt of
- Just ils -> return (Image (toList ils) (src, "fig:"))
- Nothing -> return (Image alt (src,tit))
+ return $ case mbcapt of
+ Just ils -> Image (toList ils) (src, "fig:")
+ Nothing -> Image alt (src,tit)
go x = return x
addTableCaption :: Blocks -> LP Blocks
addTableCaption = walkM go
where go (Table c als ws hs rs) = do
mbcapt <- stateCaption <$> getState
- case mbcapt of
- Just ils -> return (Table (toList ils) als ws hs rs)
- Nothing -> return (Table c als ws hs rs)
+ return $ case mbcapt of
+ Just ils -> Table (toList ils) als ws hs rs
+ Nothing -> Table c als ws hs rs
go x = return x
environments :: M.Map String (LP Blocks)
environments = M.fromList
[ ("document", env "document" blocks <* skipMany anyChar)
- , ("letter", env "letter" letter_contents)
+ , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
+ , ("letter", env "letter" letterContents)
, ("figure", env "figure" $
resetCaption *> skipopts *> blocks >>= addImageCaption)
, ("center", env "center" blocks)
, ("table", env "table" $
resetCaption *> skipopts *> blocks >>= addTableCaption)
- , ("tabular", env "tabular" simpTable)
+ , ("tabular*", env "tabular" $ simpTable True)
+ , ("tabular", env "tabular" $ simpTable False)
, ("quote", blockQuote <$> env "quote" blocks)
, ("quotation", blockQuote <$> env "quotation" blocks)
, ("verse", blockQuote <$> env "verse" blocks)
, ("itemize", bulletList <$> listenv "itemize" (many item))
, ("description", definitionList <$> listenv "description" (many descItem))
- , ("enumerate", ordered_list)
+ , ("enumerate", orderedList')
, ("alltt", alltt =<< verbEnv "alltt")
, ("code", guardEnabled Ext_literate_haskell *>
(codeBlockWith ("",["sourceCode","literate","haskell"],[]) <$>
verbEnv "code"))
- , ("verbatim", codeBlock <$> (verbEnv "verbatim"))
+ , ("verbatim", codeBlock <$> verbEnv "verbatim")
, ("Verbatim", do options <- option [] keyvals
let kvs = [ (if k == "firstnumber"
then "startFrom"
@@ -996,17 +1043,17 @@ environments = M.fromList
let classes = [ "numberLines" |
lookup "numbers" options == Just "left" ]
let attr = ("",classes,kvs)
- codeBlockWith attr <$> (verbEnv "Verbatim"))
+ codeBlockWith attr <$> verbEnv "Verbatim")
, ("lstlisting", do options <- option [] keyvals
let kvs = [ (if k == "firstnumber"
then "startFrom"
else k, v) | (k,v) <- options ]
let classes = [ "numberLines" |
lookup "numbers" options == Just "left" ]
- ++ maybe [] (:[]) (lookup "language" options
+ ++ maybeToList (lookup "language" options
>>= fromListingsLanguage)
let attr = (fromMaybe "" (lookup "label" options),classes,kvs)
- codeBlockWith attr <$> (verbEnv "lstlisting"))
+ codeBlockWith attr <$> verbEnv "lstlisting")
, ("minted", do options <- option [] keyvals
lang <- grouped (many1 $ satisfy (/='}'))
let kvs = [ (if k == "firstnumber"
@@ -1016,27 +1063,27 @@ environments = M.fromList
[ "numberLines" |
lookup "linenos" options == Just "true" ]
let attr = ("",classes,kvs)
- codeBlockWith attr <$> (verbEnv "minted"))
+ codeBlockWith attr <$> verbEnv "minted")
, ("obeylines", parseFromString
(para . trimInlines . mconcat <$> many inline) =<<
intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
- , ("displaymath", mathEnv Nothing "displaymath")
- , ("equation", mathEnv Nothing "equation")
- , ("equation*", mathEnv Nothing "equation*")
- , ("gather", mathEnv (Just "gathered") "gather")
- , ("gather*", mathEnv (Just "gathered") "gather*")
- , ("multline", mathEnv (Just "gathered") "multline")
- , ("multline*", mathEnv (Just "gathered") "multline*")
- , ("eqnarray", mathEnv (Just "aligned") "eqnarray")
- , ("eqnarray*", mathEnv (Just "aligned") "eqnarray*")
- , ("align", mathEnv (Just "aligned") "align")
- , ("align*", mathEnv (Just "aligned") "align*")
- , ("alignat", mathEnv (Just "aligned") "alignat")
- , ("alignat*", mathEnv (Just "aligned") "alignat*")
+ , ("displaymath", mathEnv para Nothing "displaymath")
+ , ("equation", mathEnv para Nothing "equation")
+ , ("equation*", mathEnv para Nothing "equation*")
+ , ("gather", mathEnv para (Just "gathered") "gather")
+ , ("gather*", mathEnv para (Just "gathered") "gather*")
+ , ("multline", mathEnv para (Just "gathered") "multline")
+ , ("multline*", mathEnv para (Just "gathered") "multline*")
+ , ("eqnarray", mathEnv para (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnv para (Just "aligned") "eqnarray*")
+ , ("align", mathEnv para (Just "aligned") "align")
+ , ("align*", mathEnv para (Just "aligned") "align*")
+ , ("alignat", mathEnv para (Just "aligned") "alignat")
+ , ("alignat*", mathEnv para (Just "aligned") "alignat*")
]
-letter_contents :: LP Blocks
-letter_contents = do
+letterContents :: LP Blocks
+letterContents = do
bs <- blocks
st <- getState
-- add signature (author) and address (title)
@@ -1063,8 +1110,8 @@ closing = do
item :: LP Blocks
item = blocks *> controlSeq "item" *> skipopts *> blocks
-loose_item :: LP Blocks
-loose_item = do
+looseItem :: LP Blocks
+looseItem = do
ctx <- stateParserContext `fmap` getState
if ctx == ListItemState
then mzero
@@ -1092,8 +1139,8 @@ listenv name p = try $ do
updateState $ \st -> st{ stateParserContext = oldCtx }
return res
-mathEnv :: Maybe String -> String -> LP Blocks
-mathEnv innerEnv name = para <$> mathDisplay (inner <$> verbEnv name)
+mathEnv :: (Inlines -> a) -> Maybe String -> String -> LP a
+mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name)
where inner x = case innerEnv of
Nothing -> x
Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
@@ -1107,8 +1154,8 @@ verbEnv name = do
res <- manyTill anyChar endEnv
return $ stripTrailingNewlines res
-ordered_list :: LP Blocks
-ordered_list = do
+orderedList' :: LP Blocks
+orderedList' = do
optional sp
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
try $ char '[' *> anyOrderedListMarker <* char ']'
@@ -1120,7 +1167,7 @@ ordered_list = do
optional sp
num <- grouped (many1 digit)
spaces
- return $ (read num + 1 :: Int)
+ return (read num + 1 :: Int)
bs <- listenv "enumerate" (many item)
return $ orderedListWith (start, style, delim) bs
@@ -1134,14 +1181,14 @@ paragraph = do
preamble :: LP Blocks
preamble = mempty <$> manyTill preambleBlock beginDoc
where beginDoc = lookAhead $ try $ controlSeq "begin" *> string "{document}"
- preambleBlock = (void comment)
- <|> (void sp)
- <|> (void blanklines)
- <|> (void macro)
- <|> (void blockCommand)
- <|> (void anyControlSeq)
- <|> (void braced)
- <|> (void anyChar)
+ preambleBlock = void comment
+ <|> void sp
+ <|> void blanklines
+ <|> void macro
+ <|> void blockCommand
+ <|> void anyControlSeq
+ <|> void braced
+ <|> void anyChar
-------
@@ -1183,7 +1230,7 @@ citationLabel = optional sp *>
<* optional sp
<* optional (char ',')
<* optional sp)
- where isBibtexKeyChar c = isAlphaNum c || c `elem` ".:;?!`'()/*@_+=-[]*"
+ where isBibtexKeyChar c = isAlphaNum c || c `elem` (".:;?!`'()/*@_+=-[]*" :: String)
cites :: CitationMode -> Bool -> LP [Citation]
cites mode multi = try $ do
@@ -1217,7 +1264,7 @@ complexNatbibCitation mode = try $ do
suff <- ils
skipSpaces
optional $ char ';'
- return $ addPrefix pref $ addSuffix suff $ cits'
+ return $ addPrefix pref $ addSuffix suff cits'
(c:cits, raw) <- withRaw $ grouped parseOne
return $ cite (c{ citationMode = mode }:cits)
(rawInline "latex" $ "\\citetext" ++ raw)
@@ -1227,7 +1274,7 @@ complexNatbibCitation mode = try $ do
parseAligns :: LP [Alignment]
parseAligns = try $ do
char '{'
- let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ try (string "@{}")
+ let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
maybeBar
let cAlign = AlignCenter <$ char 'c'
let lAlign = AlignLeft <$ char 'l'
@@ -1241,13 +1288,22 @@ parseAligns = try $ do
return aligns'
hline :: LP ()
-hline = () <$ (try $ spaces >> controlSeq "hline")
+hline = try $ do
+ spaces'
+ controlSeq "hline" <|>
+ -- booktabs rules:
+ controlSeq "toprule" <|>
+ controlSeq "bottomrule" <|>
+ controlSeq "midrule"
+ spaces'
+ optional $ bracketed (many1 (satisfy (/=']')))
+ return ()
lbreak :: LP ()
-lbreak = () <$ (try $ spaces *> controlSeq "\\")
+lbreak = () <$ try (spaces' *> controlSeq "\\" <* spaces')
amp :: LP ()
-amp = () <$ (try $ spaces *> char '&')
+amp = () <$ try (spaces' *> char '&')
parseTableRow :: Int -- ^ number of columns
-> LP [Blocks]
@@ -1260,19 +1316,22 @@ parseTableRow cols = try $ do
guard $ cells' /= [mempty]
-- note: a & b in a three-column table leaves an empty 3rd cell:
let cells'' = cells' ++ replicate (cols - numcells) mempty
- spaces
+ spaces'
return cells''
-simpTable :: LP Blocks
-simpTable = try $ do
- spaces
+spaces' :: LP ()
+spaces' = spaces *> skipMany (comment *> spaces)
+
+simpTable :: Bool -> LP Blocks
+simpTable hasWidthParameter = try $ do
+ when hasWidthParameter $ () <$ (spaces' >> tok)
+ skipopts
aligns <- parseAligns
let cols = length aligns
optional hline
header' <- option [] $ try (parseTableRow cols <* lbreak <* hline)
rows <- sepEndBy (parseTableRow cols) (lbreak <* optional hline)
- spaces
- skipMany (comment *> spaces)
+ spaces'
let header'' = if null header'
then replicate cols mempty
else header'
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 25a303f52..ae81ae7fc 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE RelaxedPolyRec #-} -- needed for inlinesBetween on GHC < 7
+{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Markdown
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,7 +36,7 @@ import Data.List ( transpose, sortBy, findIndex, intersperse, intercalate )
import qualified Data.Map as M
import Data.Scientific (coefficient, base10Exponent)
import Data.Ord ( comparing )
-import Data.Char ( isAlphaNum, toLower )
+import Data.Char ( isSpace, isAlphaNum, toLower )
import Data.Maybe
import Text.Pandoc.Definition
import qualified Data.Text as T
@@ -55,7 +56,7 @@ import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
import Text.Pandoc.Readers.HTML ( htmlTag, htmlInBalanced, isInlineTag, isBlockTag,
isTextTag, isCommentTag )
import Data.Monoid (mconcat, mempty)
-import Control.Applicative ((<$>), (<*), (*>), (<$))
+import Control.Applicative ((<$>), (<*), (*>), (<$), (<*>))
import Control.Monad
import System.FilePath (takeExtension, addExtension)
import Text.HTML.TagSoup
@@ -63,13 +64,14 @@ import Text.HTML.TagSoup.Match (tagOpen)
import qualified Data.Set as Set
import Text.Printf (printf)
import Debug.Trace (trace)
+import Text.Pandoc.Error
type MarkdownParser = Parser [Char] ParserState
-- | Read markdown from an input string and return a Pandoc document.
readMarkdown :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readMarkdown opts s =
(readWith parseMarkdown) def{ stateOptions = opts } (s ++ "\n\n")
@@ -77,13 +79,9 @@ readMarkdown opts s =
-- and a list of warnings.
readMarkdownWithWarnings :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> (Pandoc, [String])
+ -> Either PandocError (Pandoc, [String])
readMarkdownWithWarnings opts s =
- (readWith parseMarkdownWithWarnings) def{ stateOptions = opts } (s ++ "\n\n")
- where parseMarkdownWithWarnings = do
- doc <- parseMarkdown
- warnings <- stateWarnings <$> getState
- return (doc, warnings)
+ (readWithWarnings parseMarkdown) def{ stateOptions = opts } (s ++ "\n\n")
trimInlinesF :: F Inlines -> F Inlines
trimInlinesF = liftM trimInlines
@@ -117,6 +115,12 @@ isBlank _ = False
-- auxiliary functions
--
+-- | Succeeds when we're in list context.
+inList :: MarkdownParser ()
+inList = do
+ ctx <- stateParserContext <$> getState
+ guard (ctx == ListItemState)
+
isNull :: F Inlines -> Bool
isNull ils = B.isNull $ runF ils def
@@ -161,19 +165,23 @@ litChar = escapedChar'
-- | Parse a sequence of inline elements between square brackets,
-- including inlines between balanced pairs of square brackets.
inlinesInBalancedBrackets :: MarkdownParser (F Inlines)
-inlinesInBalancedBrackets = charsInBalancedBrackets >>=
- parseFromString (trimInlinesF . mconcat <$> many inline)
-
-charsInBalancedBrackets :: MarkdownParser [Char]
-charsInBalancedBrackets = do
+inlinesInBalancedBrackets = do
char '['
- result <- manyTill ( many1 (noneOf "`[]\n")
- <|> (snd <$> withRaw code)
- <|> ((\xs -> '[' : xs ++ "]") <$> charsInBalancedBrackets)
- <|> count 1 (satisfy (/='\n'))
- <|> (newline >> notFollowedBy blankline >> return "\n")
- ) (char ']')
- return $ concat result
+ (_, raw) <- withRaw $ charsInBalancedBrackets 1
+ guard $ not $ null raw
+ parseFromString (trimInlinesF . mconcat <$> many inline) (init raw)
+
+charsInBalancedBrackets :: Int -> MarkdownParser ()
+charsInBalancedBrackets 0 = return ()
+charsInBalancedBrackets openBrackets =
+ (char '[' >> charsInBalancedBrackets (openBrackets + 1))
+ <|> (char ']' >> charsInBalancedBrackets (openBrackets - 1))
+ <|> (( (() <$ code)
+ <|> (() <$ (escapedChar'))
+ <|> (newline >> notFollowedBy blankline)
+ <|> skipMany1 (noneOf "[]`\n\\")
+ <|> (() <$ count 1 (oneOf "`\\"))
+ ) >> charsInBalancedBrackets openBrackets)
--
-- document structure
@@ -243,8 +251,9 @@ yamlMetaBlock = try $ do
H.foldrWithKey (\k v m ->
if ignorable k
then m
- else B.setMeta (T.unpack k)
- (yamlToMeta opts v) m)
+ else case yamlToMeta opts v of
+ Left _ -> m
+ Right v' -> B.setMeta (T.unpack k) v' m)
nullMeta hashmap
Right Yaml.Null -> return $ return nullMeta
Right _ -> do
@@ -276,33 +285,42 @@ yamlMetaBlock = try $ do
ignorable :: Text -> Bool
ignorable t = (T.pack "_") `T.isSuffixOf` t
-toMetaValue :: ReaderOptions -> Text -> MetaValue
-toMetaValue opts x =
- case readMarkdown opts (T.unpack x) of
- Pandoc _ [Plain xs] -> MetaInlines xs
- Pandoc _ [Para xs]
+toMetaValue :: ReaderOptions -> Text -> Either PandocError MetaValue
+toMetaValue opts x = toMeta <$> readMarkdown opts' (T.unpack x)
+ where
+ toMeta p =
+ case p of
+ Pandoc _ [Plain xs] -> MetaInlines xs
+ Pandoc _ [Para xs]
| endsWithNewline x -> MetaBlocks [Para xs]
| otherwise -> MetaInlines xs
- Pandoc _ bs -> MetaBlocks bs
- where endsWithNewline t = (T.pack "\n") `T.isSuffixOf` t
-
-yamlToMeta :: ReaderOptions -> Yaml.Value -> MetaValue
+ Pandoc _ bs -> MetaBlocks bs
+ endsWithNewline t = T.pack "\n" `T.isSuffixOf` t
+ opts' = opts{readerExtensions=readerExtensions opts `Set.difference` meta_exts}
+ meta_exts = Set.fromList [ Ext_pandoc_title_block
+ , Ext_mmd_title_block
+ , Ext_yaml_metadata_block
+ ]
+
+yamlToMeta :: ReaderOptions -> Yaml.Value -> Either PandocError MetaValue
yamlToMeta opts (Yaml.String t) = toMetaValue opts t
yamlToMeta _ (Yaml.Number n)
-- avoid decimal points for numbers that don't need them:
- | base10Exponent n >= 0 = MetaString $ show
+ | base10Exponent n >= 0 = return $ MetaString $ show
$ coefficient n * (10 ^ base10Exponent n)
- | otherwise = MetaString $ show n
-yamlToMeta _ (Yaml.Bool b) = MetaBool b
-yamlToMeta opts (Yaml.Array xs) = B.toMetaValue $ map (yamlToMeta opts)
- $ V.toList xs
-yamlToMeta opts (Yaml.Object o) = MetaMap $ H.foldrWithKey (\k v m ->
+ | otherwise = return $ MetaString $ show n
+yamlToMeta _ (Yaml.Bool b) = return $ MetaBool b
+yamlToMeta opts (Yaml.Array xs) = B.toMetaValue <$> mapM (yamlToMeta opts)
+ (V.toList xs)
+yamlToMeta opts (Yaml.Object o) = MetaMap <$> H.foldrWithKey (\k v m ->
if ignorable k
then m
- else M.insert (T.unpack k)
- (yamlToMeta opts v) m)
- M.empty o
-yamlToMeta _ _ = MetaString ""
+ else (do
+ v' <- yamlToMeta opts v
+ m' <- m
+ return (M.insert (T.unpack k) v' m')))
+ (return M.empty) o
+yamlToMeta _ _ = return $ MetaString ""
stopLine :: MarkdownParser ()
stopLine = try $ (string "---" <|> string "...") >> blankline >> return ()
@@ -318,11 +336,15 @@ mmdTitleBlock = try $ do
kvPair :: MarkdownParser (String, MetaValue)
kvPair = try $ do
key <- many1Till (alphaNum <|> oneOf "_- ") (char ':')
+ skipMany1 spaceNoNewline
val <- manyTill anyChar
(try $ newline >> lookAhead (blankline <|> nonspaceChar))
+ guard $ not . null . trim $ val
let key' = concat $ words $ map toLower key
let val' = MetaBlocks $ B.toList $ B.plain $ B.text $ trim val
return (key',val')
+ where
+ spaceNoNewline = satisfy (\x -> isSpace x && (x/='\n') && (x/='\r'))
parseMarkdown :: MarkdownParser Pandoc
parseMarkdown = do
@@ -337,12 +359,6 @@ parseMarkdown = do
let Pandoc _ bs = B.doc $ runF blocks st
return $ Pandoc meta bs
-addWarning :: Maybe SourcePos -> String -> MarkdownParser ()
-addWarning mbpos msg =
- updateState $ \st -> st{
- stateWarnings = (msg ++ maybe "" (\pos -> " " ++ show pos) mbpos) :
- stateWarnings st }
-
referenceKey :: MarkdownParser (F Blocks)
referenceKey = try $ do
pos <- getPosition
@@ -458,12 +474,12 @@ block = do
, bulletList
, header
, lhsCodeBlock
- , rawTeXBlock
, divHtml
, htmlBlock
, table
- , lineBlock
, codeBlockIndented
+ , rawTeXBlock
+ , lineBlock
, blockQuote
, hrule
, orderedList
@@ -499,9 +515,12 @@ atxHeader = try $ do
notFollowedBy $ guardEnabled Ext_fancy_lists >>
(char '.' <|> char ')') -- this would be a list
skipSpaces
- text <- trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
+ (text, raw) <- withRaw $
+ trimInlinesF . mconcat <$> many (notFollowedBy atxClosing >> inline)
attr <- atxClosing
- attr' <- registerHeader attr (runF text defaultParserState)
+ attr'@(ident,_,_) <- registerHeader attr (runF text defaultParserState)
+ guardDisabled Ext_implicit_header_references
+ <|> registerImplicitHeader raw ident
return $ B.headerWith attr' level <$> text
atxClosing :: MarkdownParser Attr
@@ -534,15 +553,25 @@ setextHeader = try $ do
-- This lookahead prevents us from wasting time parsing Inlines
-- unless necessary -- it gives a significant performance boost.
lookAhead $ anyLine >> many1 (oneOf setextHChars) >> blankline
- text <- trimInlinesF . mconcat <$> many1 (notFollowedBy setextHeaderEnd >> inline)
+ skipSpaces
+ (text, raw) <- withRaw $
+ trimInlinesF . mconcat <$> many1 (notFollowedBy setextHeaderEnd >> inline)
attr <- setextHeaderEnd
underlineChar <- oneOf setextHChars
many (char underlineChar)
blanklines
let level = (fromMaybe 0 $ findIndex (== underlineChar) setextHChars) + 1
- attr' <- registerHeader attr (runF text defaultParserState)
+ attr'@(ident,_,_) <- registerHeader attr (runF text defaultParserState)
+ guardDisabled Ext_implicit_header_references
+ <|> registerImplicitHeader raw ident
return $ B.headerWith attr' level <$> text
+registerImplicitHeader :: String -> String -> MarkdownParser ()
+registerImplicitHeader raw ident = do
+ let key = toKey $ "[" ++ raw ++ "]"
+ updateState (\s -> s { stateHeaderKeys =
+ M.insert key ('#':ident,"") (stateHeaderKeys s) })
+
--
-- hrule block
--
@@ -741,9 +770,9 @@ anyOrderedListStart = try $ do
skipNonindentSpaces
notFollowedBy $ string "p." >> spaceChar >> digit -- page number
res <- do guardDisabled Ext_fancy_lists
- many1 digit
+ start <- many1 digit >>= safeRead
char '.'
- return (1, DefaultStyle, DefaultDelim)
+ return (start, DefaultStyle, DefaultDelim)
<|> do (num, style, delim) <- anyOrderedListMarker
-- if it could be an abbreviated first name,
-- insist on more than one space
@@ -865,7 +894,7 @@ defListMarker = do
tabStop <- getOption readerTabStop
let remaining = tabStop - (length sps + 1)
if remaining > 0
- then count remaining (char ' ') <|> string "\t"
+ then try (count remaining (char ' ')) <|> string "\t" <|> many1 spaceChar
else mzero
return ()
@@ -874,7 +903,7 @@ definitionListItem compact = try $ do
rawLine' <- anyLine
raw <- many1 $ defRawBlock compact
term <- parseFromString (trimInlinesF . mconcat <$> many inline) rawLine'
- contents <- mapM (parseFromString parseBlocks) raw
+ contents <- mapM (parseFromString parseBlocks . (++"\n")) raw
optional blanklines
return $ liftM2 (,) term (sequence contents)
@@ -885,6 +914,7 @@ defRawBlock compact = try $ do
firstline <- anyLine
let dline = try
( do notFollowedBy blankline
+ notFollowedByHtmlCloser
if compact -- laziness not compatible with compact
then () <$ indentSpaces
else (() <$ indentSpaces)
@@ -901,7 +931,10 @@ defRawBlock compact = try $ do
definitionList :: MarkdownParser (F Blocks)
definitionList = try $ do
- lookAhead (anyLine >> optional blankline >> defListMarker)
+ lookAhead (anyLine >>
+ optional (blankline >> notFollowedBy (table >> return ())) >>
+ -- don't capture table caption as def list!
+ defListMarker)
compactDefinitionList <|> normalDefinitionList
compactDefinitionList :: MarkdownParser (F Blocks)
@@ -932,6 +965,8 @@ para = try $ do
<|> (guardEnabled Ext_backtick_code_blocks >> () <$ lookAhead codeBlockFenced)
<|> (guardDisabled Ext_blank_before_header >> () <$ lookAhead header)
<|> (guardEnabled Ext_lists_without_preceding_blankline >>
+ -- Avoid creating a paragraph in a nested list.
+ notFollowedBy' inList >>
() <$ lookAhead listStart)
<|> do guardEnabled Ext_native_divs
inHtmlBlock <- stateInHtmlBlock <$> getState
@@ -1062,7 +1097,9 @@ dashedLine :: Char
dashedLine ch = do
dashes <- many1 (char ch)
sp <- many spaceChar
- return $ (length dashes, length $ dashes ++ sp)
+ let lengthDashes = length dashes
+ lengthSp = length sp
+ return (lengthDashes, lengthDashes + lengthSp)
-- Parse a table header with dashed lines of '-' preceded by
-- one (or zero) line of text.
@@ -1216,7 +1253,8 @@ gridPart :: Char -> Parser [Char] st (Int, Int)
gridPart ch = do
dashes <- many1 (char ch)
char '+'
- return (length dashes, length dashes + 1)
+ let lengthDashes = length dashes
+ return (lengthDashes, lengthDashes + 1)
gridDashedLines :: Char -> Parser [Char] st [(Int,Int)]
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
@@ -1295,12 +1333,8 @@ pipeBreak = try $ do
pipeTable :: MarkdownParser ([Alignment], [Double], F [Blocks], F [[Blocks]])
pipeTable = try $ do
- (heads,aligns) <- try ( pipeBreak >>= \als ->
- return (return $ replicate (length als) mempty, als))
- <|> ( pipeTableRow >>= \row -> pipeBreak >>= \als ->
-
- return (row, als) )
- lines' <- sequence <$> many1 pipeTableRow
+ (heads,aligns) <- (,) <$> pipeTableRow <*> pipeBreak
+ lines' <- sequence <$> many pipeTableRow
let widths = replicate (length aligns) 0.0
return $ (aligns, widths, heads, lines')
@@ -1482,7 +1516,9 @@ code = try $ do
math :: MarkdownParser (F Inlines)
math = (return . B.displayMath <$> (mathDisplay >>= applyMacros'))
- <|> (return . B.math <$> (mathInline >>= applyMacros'))
+ <|> (return . B.math <$> (mathInline >>= applyMacros')) <+?>
+ ((getOption readerSmart >>= guard) *> (return <$> apostrophe)
+ <* notFollowedBy space)
-- Parses material enclosed in *s, **s, _s, or __s.
-- Designed to avoid backtracking.
@@ -1616,8 +1652,7 @@ endline = try $ do
newline
notFollowedBy blankline
-- parse potential list-starts differently if in a list:
- st <- getState
- when (stateParserContext st == ListItemState) $ notFollowedBy listStart
+ notFollowedBy (inList >> listStart)
guardDisabled Ext_lists_without_preceding_blankline <|> notFollowedBy listStart
guardEnabled Ext_blank_before_blockquote <|> notFollowedBy emailBlockQuoteStart
guardEnabled Ext_blank_before_header <|> (notFollowedBy . char =<< atxChar) -- atx header
@@ -1684,9 +1719,11 @@ referenceLink :: (String -> String -> Inlines -> Inlines)
-> (F Inlines, String) -> MarkdownParser (F Inlines)
referenceLink constructor (lab, raw) = do
sp <- (True <$ lookAhead (char ' ')) <|> return False
- (ref,raw') <- try
- (skipSpaces >> optional (newline >> skipSpaces) >> reference)
- <|> return (mempty, "")
+ (_,raw') <- option (mempty, "") $
+ lookAhead (try (spnl >> normalCite >> return (mempty, "")))
+ <|>
+ try (spnl >> reference)
+ when (raw' == "") $ guardEnabled Ext_shortcut_reference_links
let labIsRef = raw' == "" || raw' == "[]"
let key = toKey $ if labIsRef then raw else raw'
parsedRaw <- parseFromString (mconcat <$> many inline) raw'
@@ -1702,13 +1739,13 @@ referenceLink constructor (lab, raw) = do
return $ do
keys <- asksF stateKeys
case M.lookup key keys of
- Nothing -> do
- headers <- asksF stateHeaders
- ref' <- if labIsRef then lab else ref
+ Nothing ->
if implicitHeaderRefs
- then case M.lookup ref' headers of
- Just ident -> constructor ('#':ident) "" <$> lab
- Nothing -> makeFallback
+ then do
+ headerKeys <- asksF stateHeaderKeys
+ case M.lookup key headerKeys of
+ Just (src, tit) -> constructor src tit <$> lab
+ Nothing -> makeFallback
else makeFallback
Just (src,tit) -> constructor src tit <$> lab
@@ -1722,12 +1759,14 @@ dropBrackets = reverse . dropRB . reverse . dropLB
bareURL :: MarkdownParser (F Inlines)
bareURL = try $ do
guardEnabled Ext_autolink_bare_uris
+ getState >>= guard . stateAllowLinks
(orig, src) <- uri <|> emailAddress
notFollowedBy $ try $ spaces >> htmlTag (~== TagClose "a")
return $ return $ B.link src "" (B.str orig)
autoLink :: MarkdownParser (F Inlines)
autoLink = try $ do
+ getState >>= guard . stateAllowLinks
char '<'
(orig, src) <- uri <|> emailAddress
-- in rare cases, something may remain after the uri parser
@@ -1874,8 +1913,20 @@ textualCite = try $ do
return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw) . (first:))
<$> rest
Nothing ->
- (do (cs, raw) <- withRaw $ bareloc first
- return $ (flip B.cite (B.text $ '@':key ++ " " ++ raw)) <$> cs)
+ (do
+ (cs, raw) <- withRaw $ bareloc first
+ let (spaces',raw') = span isSpace raw
+ spc | null spaces' = mempty
+ | otherwise = B.space
+ lab <- parseFromString (mconcat <$> many inline) $ dropBrackets raw'
+ fallback <- referenceLink B.link (lab,raw')
+ return $ do
+ fallback' <- fallback
+ cs' <- cs
+ return $
+ case B.toList fallback' of
+ Link{}:_ -> B.cite [first] (B.str $ '@':key) <> spc <> fallback'
+ _ -> B.cite cs' (B.text $ '@':key ++ " " ++ raw))
<|> return (do st <- askF
return $ case M.lookup key (stateExamples st) of
Just n -> B.str (show n)
@@ -1885,10 +1936,12 @@ bareloc :: Citation -> MarkdownParser (F [Citation])
bareloc c = try $ do
spnl
char '['
+ notFollowedBy $ char '^'
suff <- suffix
rest <- option (return []) $ try $ char ';' >> citeList
spnl
char ']'
+ notFollowedBy $ oneOf "[("
return $ do
suff' <- suff
rest' <- rest
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index e43b8a86c..2a5adab22 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE RelaxedPolyRec, FlexibleInstances, TypeSynonymInstances #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
- Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.MediaWiki
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -58,21 +58,21 @@ import Data.Maybe (fromMaybe)
import Text.Printf (printf)
import Debug.Trace (trace)
+import Text.Pandoc.Error
+
-- | Read mediawiki from an input string and return a Pandoc document.
readMediaWiki :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readMediaWiki opts s =
- case runParser parseMediaWiki MWState{ mwOptions = opts
+ readWith parseMediaWiki MWState{ mwOptions = opts
, mwMaxNestingLevel = 4
, mwNextLinkNumber = 1
, mwCategoryLinks = []
, mwHeaderMap = M.empty
, mwIdentifierList = []
}
- "source" (s ++ "\n") of
- Left err' -> error $ "\nError:\n" ++ show err'
- Right result -> result
+ (s ++ "\n")
data MWState = MWState { mwOptions :: ReaderOptions
, mwMaxNestingLevel :: Int
@@ -593,11 +593,17 @@ imageOption =
<|> try (many1 (oneOf "x0123456789") <* string "px")
<|> try (oneOfStrings ["link=","alt=","page=","class="] <* many (noneOf "|]"))
+collapseUnderscores :: String -> String
+collapseUnderscores [] = []
+collapseUnderscores ('_':'_':xs) = collapseUnderscores ('_':xs)
+collapseUnderscores (x:xs) = x : collapseUnderscores xs
+
+addUnderscores :: String -> String
+addUnderscores = collapseUnderscores . intercalate "_" . words
+
internalLink :: MWParser Inlines
internalLink = try $ do
sym "[["
- let addUnderscores x = let (pref,suff) = break (=='#') x
- in pref ++ intercalate "_" (words suff)
pagename <- unwords . words <$> many (noneOf "|]")
label <- option (B.text pagename) $ char '|' *>
( (mconcat <$> many1 (notFollowedBy (char ']') *> inline))
diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs
index f4dfa62c1..94ea9e3a2 100644
--- a/src/Text/Pandoc/Readers/Native.hs
+++ b/src/Text/Pandoc/Readers/Native.hs
@@ -1,9 +1,9 @@
{-
-Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
+the Free Software Foundation; Either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Native
- Copyright : Copyright (C) 2011-2014 John MacFarlane
+ Copyright : Copyright (C) 2011-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,6 +33,9 @@ module Text.Pandoc.Readers.Native ( readNative ) where
import Text.Pandoc.Definition
import Text.Pandoc.Shared (safeRead)
+import Text.Pandoc.Error
+import Control.Applicative
+
-- | Read native formatted text and return a Pandoc document.
-- The input may be a full pandoc document, a block list, a block,
-- an inline list, or an inline. Thus, for example,
@@ -44,33 +47,18 @@ import Text.Pandoc.Shared (safeRead)
-- > Pandoc nullMeta [Plain [Str "hi"]]
--
readNative :: String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
-readNative s =
- case safeRead s of
- Just d -> d
- Nothing -> Pandoc nullMeta $ readBlocks s
+ -> Either PandocError Pandoc
+readNative s = maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s)
-readBlocks :: String -> [Block]
-readBlocks s =
- case safeRead s of
- Just d -> d
- Nothing -> [readBlock s]
+readBlocks :: String -> Either PandocError [Block]
+readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
-readBlock :: String -> Block
-readBlock s =
- case safeRead s of
- Just d -> d
- Nothing -> Plain $ readInlines s
+readBlock :: String -> Either PandocError Block
+readBlock s = maybe (Plain <$> readInlines s) Right (safeRead s)
-readInlines :: String -> [Inline]
-readInlines s =
- case safeRead s of
- Just d -> d
- Nothing -> [readInline s]
+readInlines :: String -> Either PandocError [Inline]
+readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead s)
-readInline :: String -> Inline
-readInline s =
- case safeRead s of
- Just d -> d
- Nothing -> error "Cannot parse document"
+readInline :: String -> Either PandocError Inline
+readInline s = maybe (Left . ParseFailure $ "Could not read: " ++ s) Right (safeRead s)
diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs
index 35d01e877..19ddba36b 100644
--- a/src/Text/Pandoc/Readers/OPML.hs
+++ b/src/Text/Pandoc/Readers/OPML.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE FlexibleContexts #-}
module Text.Pandoc.Readers.OPML ( readOPML ) where
import Data.Char (toUpper)
import Text.Pandoc.Options
@@ -11,8 +12,11 @@ import Data.Generics
import Data.Monoid
import Control.Monad.State
import Control.Applicative ((<$>), (<$))
+import Data.Default
+import Text.Pandoc.Compat.Except
+import Text.Pandoc.Error
-type OPML = State OPMLState
+type OPML = ExceptT PandocError (State OPMLState)
data OPMLState = OPMLState{
opmlSectionLevel :: Int
@@ -21,17 +25,19 @@ data OPMLState = OPMLState{
, opmlDocDate :: Inlines
} deriving Show
-readOPML :: ReaderOptions -> String -> Pandoc
+instance Default OPMLState where
+ def = OPMLState{ opmlSectionLevel = 0
+ , opmlDocTitle = mempty
+ , opmlDocAuthors = []
+ , opmlDocDate = mempty
+ }
+
+readOPML :: ReaderOptions -> String -> Either PandocError Pandoc
readOPML _ inp = setTitle (opmlDocTitle st')
- $ setAuthors (opmlDocAuthors st')
- $ setDate (opmlDocDate st')
- $ doc $ mconcat bs
- where (bs, st') = runState (mapM parseBlock $ normalizeTree $ parseXML inp)
- OPMLState{ opmlSectionLevel = 0
- , opmlDocTitle = mempty
- , opmlDocAuthors = []
- , opmlDocDate = mempty
- }
+ . setAuthors (opmlDocAuthors st')
+ . setDate (opmlDocDate st')
+ . doc . mconcat <$> bs
+ where (bs, st') = flip runState def . runExceptT $ (mapM parseBlock $ normalizeTree $ parseXML inp)
-- normalize input, consolidating adjacent Text and CRef elements
normalizeTree :: [Content] -> [Content]
@@ -58,14 +64,16 @@ attrValue attr elt =
Just z -> z
Nothing -> ""
-asHtml :: String -> Inlines
-asHtml s = case readHtml def s of
- Pandoc _ [Plain ils] -> fromList ils
- _ -> mempty
+exceptT :: Either PandocError a -> OPML a
+exceptT = either throwError return
+
+asHtml :: String -> OPML Inlines
+asHtml s = (\(Pandoc _ bs) -> case bs of
+ [Plain ils] -> fromList ils
+ _ -> mempty) <$> exceptT (readHtml def s)
-asMarkdown :: String -> Blocks
-asMarkdown s = fromList bs
- where Pandoc _ bs = readMarkdown def s
+asMarkdown :: String -> OPML Blocks
+asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> exceptT (readMarkdown def s)
getBlocks :: Element -> OPML Blocks
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
@@ -82,8 +90,8 @@ parseBlock (Elem e) =
"outline" -> gets opmlSectionLevel >>= sect . (+1)
"?xml" -> return mempty
_ -> getBlocks e
- where sect n = do let headerText = asHtml $ attrValue "text" e
- let noteBlocks = asMarkdown $ attrValue "_note" e
+ where sect n = do headerText <- asHtml $ attrValue "text" e
+ noteBlocks <- asMarkdown $ attrValue "_note" e
modify $ \st -> st{ opmlSectionLevel = n }
bs <- getBlocks e
modify $ \st -> st{ opmlSectionLevel = n - 1 }
diff --git a/src/Text/Pandoc/Readers/Odt.hs b/src/Text/Pandoc/Readers/Odt.hs
new file mode 100644
index 000000000..1c8ec51bc
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt.hs
@@ -0,0 +1,86 @@
+{-# LANGUAGE PatternGuards #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Reader.Odt
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Entry point to the odt reader.
+-}
+
+module Text.Pandoc.Readers.Odt ( readOdt ) where
+
+import Codec.Archive.Zip
+import qualified Text.XML.Light as XML
+
+import qualified Data.ByteString.Lazy as B
+import Data.Monoid ( mempty )
+
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Text.Pandoc.Options
+import Text.Pandoc.MediaBag
+import qualified Text.Pandoc.UTF8 as UTF8
+
+import Text.Pandoc.Readers.Odt.ContentReader
+import Text.Pandoc.Readers.Odt.StyleReader
+
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+
+--
+readOdt :: ReaderOptions
+ -> B.ByteString
+ -> Either PandocError (Pandoc, MediaBag)
+readOdt _ bytes = case bytesToOdt bytes of
+ Right pandoc -> Right (pandoc , mempty)
+ Left err -> Left err
+
+--
+bytesToOdt :: B.ByteString -> Either PandocError Pandoc
+bytesToOdt bytes = archiveToOdt $ toArchive bytes
+
+--
+archiveToOdt :: Archive -> Either PandocError Pandoc
+archiveToOdt archive
+ | Just contentEntry <- findEntryByPath "content.xml" archive
+ , Just stylesEntry <- findEntryByPath "styles.xml" archive
+ , Just contentElem <- entryToXmlElem contentEntry
+ , Just stylesElem <- entryToXmlElem stylesEntry
+ , Right styles <- chooseMax (readStylesAt stylesElem )
+ (readStylesAt contentElem)
+ , startState <- readerState styles
+ , Right pandoc <- runConverter' read_body
+ startState
+ contentElem
+ = Right pandoc
+
+ | otherwise
+ -- Not very detailed, but I don't think more information would be helpful
+ = Left $ ParseFailure "Couldn't parse odt file."
+
+--
+entryToXmlElem :: Entry -> Maybe XML.Element
+entryToXmlElem = XML.parseXMLDoc . UTF8.toStringLazy . fromEntry
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
new file mode 100644
index 000000000..310ca028e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
@@ -0,0 +1,253 @@
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Arrows.State
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+An arrow that transports a state. It is in essence a more powerful version of
+the standard state monad. As it is such a simple extension, there are
+other version out there that do exactly the same.
+The implementation is duplicated, though, to add some useful features.
+Most of these might be implemented without access to innards, but it's much
+faster and easier to implement this way.
+-}
+
+module Text.Pandoc.Readers.Odt.Arrows.State where
+
+import Prelude hiding ( foldr, foldl )
+
+import qualified Control.Category as Cat
+import Control.Arrow
+import Control.Monad
+
+import Data.Monoid
+import Data.Foldable
+
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+
+
+newtype ArrowState state a b = ArrowState
+ { runArrowState :: (state, a) -> (state, b) }
+
+-- | Constructor
+withState :: (state -> a -> (state, b)) -> ArrowState state a b
+withState = ArrowState . uncurry
+
+-- | Constructor
+withState' :: ((state, a) -> (state, b)) -> ArrowState state a b
+withState' = ArrowState
+
+-- | Constructor
+modifyState :: (state -> state ) -> ArrowState state a a
+modifyState = ArrowState . first
+
+-- | Constructor
+ignoringState :: ( a -> b ) -> ArrowState state a b
+ignoringState = ArrowState . second
+
+-- | Constructor
+fromState :: (state -> (state, b)) -> ArrowState state a b
+fromState = ArrowState . (.fst)
+
+-- | Constructor
+extractFromState :: (state -> b ) -> ArrowState state x b
+extractFromState f = ArrowState $ \(state,_) -> (state, f state)
+
+-- | Constructor
+withUnchangedState :: (state -> a -> b ) -> ArrowState state a b
+withUnchangedState f = ArrowState $ \(state,a) -> (state, f state a)
+
+-- | Constructor
+tryModifyState :: (state -> Either f state)
+ -> ArrowState state a (Either f a)
+tryModifyState f = ArrowState $ \(state,a)
+ -> (state,).Left ||| (,Right a) $ f state
+
+instance Cat.Category (ArrowState s) where
+ id = ArrowState id
+ arrow2 . arrow1 = ArrowState $ (runArrowState arrow2).(runArrowState arrow1)
+
+instance Arrow (ArrowState state) where
+ arr = ignoringState
+ first a = ArrowState $ \(s,(aF,aS))
+ -> second (,aS) $ runArrowState a (s,aF)
+ second a = ArrowState $ \(s,(aF,aS))
+ -> second (aF,) $ runArrowState a (s,aS)
+
+instance ArrowChoice (ArrowState state) where
+ left a = ArrowState $ \(s,e) -> case e of
+ Left l -> second Left $ runArrowState a (s,l)
+ Right r -> (s, Right r)
+ right a = ArrowState $ \(s,e) -> case e of
+ Left l -> (s, Left l)
+ Right r -> second Right $ runArrowState a (s,r)
+
+instance ArrowLoop (ArrowState state) where
+ loop a = ArrowState $ \(s, x)
+ -> let (s', (x', _d)) = runArrowState a (s, (x, _d))
+ in (s', x')
+
+instance ArrowApply (ArrowState state) where
+ app = ArrowState $ \(s, (f,b)) -> runArrowState f (s,b)
+
+
+-- | Embedding of a state arrow in a state arrow with a different state type.
+switchState :: (s -> s') -> (s' -> s) -> ArrowState s' x y -> ArrowState s x y
+switchState there back a = ArrowState $ first there
+ >>> runArrowState a
+ >>> first back
+
+-- | Lift a state arrow to modify the state of an arrow
+-- with a different state type.
+liftToState :: (s -> s') -> ArrowState s' s s -> ArrowState s x x
+liftToState unlift a = modifyState $ unlift &&& id
+ >>> runArrowState a
+ >>> snd
+
+-- | Switches the type of the state temporarily.
+-- Drops the intermediate result state, behaving like the identity arrow,
+-- save for side effects in the state.
+withSubState :: ArrowState s x s2 -> ArrowState s2 s s -> ArrowState s x x
+withSubState unlift a = keepingTheValue (withSubState unlift a) >>^ fst
+
+-- | Switches the type of the state temporarily.
+-- Returns the resulting sub-state.
+withSubState' :: ArrowState s x s' -> ArrowState s' s s -> ArrowState s x s'
+withSubState' unlift a = ArrowState $ runArrowState unlift
+ >>> switch
+ >>> runArrowState a
+ >>> switch
+ where switch (x,y) = (y,x)
+
+-- | Switches the type of the state temporarily.
+-- Drops the intermediate result state, behaving like a fallible
+-- identity arrow, save for side effects in the state.
+withSubStateF :: ArrowState s x (Either f s')
+ -> ArrowState s' s (Either f s )
+ -> ArrowState s x (Either f x )
+withSubStateF unlift a = keepingTheValue (withSubStateF' unlift a)
+ >>^ spreadChoice
+ >>^ fmap fst
+
+-- | Switches the type of the state temporarily.
+-- Returns the resulting sub-state.
+withSubStateF' :: ArrowState s x (Either f s')
+ -> ArrowState s' s (Either f s )
+ -> ArrowState s x (Either f s')
+withSubStateF' unlift a = ArrowState go
+ where go p@(s,_) = tryRunning unlift
+ ( tryRunning a (second Right) )
+ p
+ where tryRunning a' b v = case runArrowState a' v of
+ (_ , Left f) -> (s, Left f)
+ (x , Right y) -> b (y,x)
+
+-- | Fold a state arrow through something 'Foldable'. Collect the results
+-- in a 'Monoid'.
+-- Intermediate form of a fold between one with "only" a 'Monoid'
+-- and one with any function.
+foldS :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
+foldS a = ArrowState $ \(s,f) -> foldr a' (s,mempty) f
+ where a' x (s',m) = second (m <>) $ runArrowState a (s',x)
+
+-- | Fold a state arrow through something 'Foldable'. Collect the results
+-- in a 'Monoid'.
+-- Intermediate form of a fold between one with "only" a 'Monoid'
+-- and one with any function.
+foldSL :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
+foldSL a = ArrowState $ \(s,f) -> foldl a' (s,mempty) f
+ where a' (s',m) x = second (m <>) $ runArrowState a (s',x)
+
+-- | Fold a fallible state arrow through something 'Foldable'. Collect the
+-- results in a 'Monoid'.
+-- Intermediate form of a fold between one with "only" a 'Monoid'
+-- and one with any function.
+-- If the iteration fails, the state will be reset to the initial one.
+foldS' :: (Foldable f, Monoid m)
+ => ArrowState s x (Either e m)
+ -> ArrowState s (f x) (Either e m)
+foldS' a = ArrowState $ \(s,f) -> foldr (a' s) (s,Right mempty) f
+ where a' s x (s',Right m) = case runArrowState a (s',x) of
+ (s'',Right m') -> (s'', Right (m <> m'))
+ (_ ,Left e ) -> (s , Left e)
+ a' _ _ e = e
+
+-- | Fold a fallible state arrow through something 'Foldable'. Collect the
+-- results in a 'Monoid'.
+-- Intermediate form of a fold between one with "only" a 'Monoid'
+-- and one with any function.
+-- If the iteration fails, the state will be reset to the initial one.
+foldSL' :: (Foldable f, Monoid m)
+ => ArrowState s x (Either e m)
+ -> ArrowState s (f x) (Either e m)
+foldSL' a = ArrowState $ \(s,f) -> foldl (a' s) (s,Right mempty) f
+ where a' s (s',Right m) x = case runArrowState a (s',x) of
+ (s'',Right m') -> (s'', Right (m <> m'))
+ (_ ,Left e ) -> (s , Left e)
+ a' _ e _ = e
+
+-- | Fold a state arrow through something 'Foldable'. Collect the results in a
+-- 'MonadPlus'.
+iterateS :: (Foldable f, MonadPlus m)
+ => ArrowState s x y
+ -> ArrowState s (f x) (m y)
+iterateS a = ArrowState $ \(s,f) -> foldr a' (s,mzero) f
+ where a' x (s',m) = second ((mplus m).return) $ runArrowState a (s',x)
+
+-- | Fold a state arrow through something 'Foldable'. Collect the results in a
+-- 'MonadPlus'.
+iterateSL :: (Foldable f, MonadPlus m)
+ => ArrowState s x y
+ -> ArrowState s (f x) (m y)
+iterateSL a = ArrowState $ \(s,f) -> foldl a' (s,mzero) f
+ where a' (s',m) x = second ((mplus m).return) $ runArrowState a (s',x)
+
+
+-- | Fold a fallible state arrow through something 'Foldable'.
+-- Collect the results in a 'MonadPlus'.
+-- If the iteration fails, the state will be reset to the initial one.
+iterateS' :: (Foldable f, MonadPlus m)
+ => ArrowState s x (Either e y )
+ -> ArrowState s (f x) (Either e (m y))
+iterateS' a = ArrowState $ \(s,f) -> foldr (a' s) (s,Right mzero) f
+ where a' s x (s',Right m) = case runArrowState a (s',x) of
+ (s'',Right m') -> (s'',Right $ mplus m $ return m')
+ (_ ,Left e ) -> (s ,Left e )
+ a' _ _ e = e
+
+-- | Fold a fallible state arrow through something 'Foldable'.
+-- Collect the results in a 'MonadPlus'.
+-- If the iteration fails, the state will be reset to the initial one.
+iterateSL' :: (Foldable f, MonadPlus m)
+ => ArrowState s x (Either e y )
+ -> ArrowState s (f x) (Either e (m y))
+iterateSL' a = ArrowState $ \(s,f) -> foldl (a' s) (s,Right mzero) f
+ where a' s (s',Right m) x = case runArrowState a (s',x) of
+ (s'',Right m') -> (s'',Right $ mplus m $ return m')
+ (_ ,Left e ) -> (s ,Left e )
+ a' _ e _ = e
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
new file mode 100644
index 000000000..9710973b3
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
@@ -0,0 +1,497 @@
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Arrows.Utils
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Utility functions for Arrows (Kleisli monads).
+
+Some general notes on notation:
+
+* "^" is meant to stand for a pure function that is lifted into an arrow
+based on its usage for that purpose in "Control.Arrow".
+* "?" is meant to stand for the usage of a 'FallibleArrow' or a pure function
+with an equivalent return value.
+* "_" stands for the dropping of a value.
+-}
+
+-- We export everything
+module Text.Pandoc.Readers.Odt.Arrows.Utils where
+
+import Control.Arrow
+import Control.Monad ( join, MonadPlus(..) )
+
+import Data.Monoid
+import qualified Data.Foldable as F
+
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.Utils
+
+
+and2 :: (Arrow a) => a b c -> a b c' -> a b (c,c')
+and2 = (&&&)
+
+and3 :: (Arrow a)
+ => a b c0->a b c1->a b c2
+ -> a b (c0,c1,c2 )
+and4 :: (Arrow a)
+ => a b c0->a b c1->a b c2->a b c3
+ -> a b (c0,c1,c2,c3 )
+and5 :: (Arrow a)
+ => a b c0->a b c1->a b c2->a b c3->a b c4
+ -> a b (c0,c1,c2,c3,c4 )
+and6 :: (Arrow a)
+ => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5
+ -> a b (c0,c1,c2,c3,c4,c5 )
+and7 :: (Arrow a)
+ => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5->a b c6
+ -> a b (c0,c1,c2,c3,c4,c5,c6 )
+and8 :: (Arrow a)
+ => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5->a b c6->a b c7
+ -> a b (c0,c1,c2,c3,c4,c5,c6,c7)
+
+and3 a b c = (and2 a b ) &&& c
+ >>^ \((z,y ) , x) -> (z,y,x )
+and4 a b c d = (and3 a b c ) &&& d
+ >>^ \((z,y,x ) , w) -> (z,y,x,w )
+and5 a b c d e = (and4 a b c d ) &&& e
+ >>^ \((z,y,x,w ) , v) -> (z,y,x,w,v )
+and6 a b c d e f = (and5 a b c d e ) &&& f
+ >>^ \((z,y,x,w,v ) , u) -> (z,y,x,w,v,u )
+and7 a b c d e f g = (and6 a b c d e f ) &&& g
+ >>^ \((z,y,x,w,v,u ) , t) -> (z,y,x,w,v,u,t )
+and8 a b c d e f g h = (and7 a b c d e f g) &&& h
+ >>^ \((z,y,x,w,v,u,t) , s) -> (z,y,x,w,v,u,t,s)
+
+liftA2 :: (Arrow a) => (x -> y -> z) -> a b x -> a b y -> a b z
+liftA2 f a b = a &&& b >>^ uncurry f
+
+liftA3 :: (Arrow a) => (z->y->x -> r)
+ -> a b z->a b y->a b x
+ -> a b r
+liftA4 :: (Arrow a) => (z->y->x->w -> r)
+ -> a b z->a b y->a b x->a b w
+ -> a b r
+liftA5 :: (Arrow a) => (z->y->x->w->v -> r)
+ -> a b z->a b y->a b x->a b w->a b v
+ -> a b r
+liftA6 :: (Arrow a) => (z->y->x->w->v->u -> r)
+ -> a b z->a b y->a b x->a b w->a b v->a b u
+ -> a b r
+liftA7 :: (Arrow a) => (z->y->x->w->v->u->t -> r)
+ -> a b z->a b y->a b x->a b w->a b v->a b u->a b t
+ -> a b r
+liftA8 :: (Arrow a) => (z->y->x->w->v->u->t->s -> r)
+ -> a b z->a b y->a b x->a b w->a b v->a b u->a b t->a b s
+ -> a b r
+
+liftA3 fun a b c = and3 a b c >>^ uncurry3 fun
+liftA4 fun a b c d = and4 a b c d >>^ uncurry4 fun
+liftA5 fun a b c d e = and5 a b c d e >>^ uncurry5 fun
+liftA6 fun a b c d e f = and6 a b c d e f >>^ uncurry6 fun
+liftA7 fun a b c d e f g = and7 a b c d e f g >>^ uncurry7 fun
+liftA8 fun a b c d e f g h = and8 a b c d e f g h >>^ uncurry8 fun
+
+liftA :: (Arrow a) => (y -> z) -> a b y -> a b z
+liftA fun a = a >>^ fun
+
+
+-- | Duplicate a value to subsequently feed it into different arrows.
+-- Can almost always be replaced with '(&&&)', 'keepingTheValue',
+-- or even '(|||)'.
+-- Aequivalent to
+-- > returnA &&& returnA
+duplicate :: (Arrow a) => a b (b,b)
+duplicate = arr $ join (,)
+
+-- | Lifts the combination of two values into an arrow.
+joinOn :: (Arrow a) => (x -> y -> z) -> a (x,y) z
+joinOn = arr.uncurry
+
+-- | Applies a function to the uncurried result-pair of an arrow-application.
+-- (The §-symbol was chosen to evoke an association with pairs through the
+-- shared first character)
+(>>§) :: (Arrow a) => a x (b,c) -> (b -> c -> d) -> a x d
+a >>§ f = a >>^ uncurry f
+
+-- | '(>>§)' with its arguments flipped
+(§<<) :: (Arrow a) => (b -> c -> d) -> a x (b,c) -> a x d
+(§<<) = flip (>>§)
+
+-- | Precomposition with an uncurried function
+(§>>) :: (Arrow a) => (b -> c -> d) -> a d r -> a (b,c) r
+f §>> a = uncurry f ^>> a
+
+-- | Precomposition with an uncurried function (right to left variant)
+(<<§) :: (Arrow a) => a d r -> (b -> c -> d) -> a (b,c) r
+(<<§) = flip (§>>)
+
+infixr 2 >>§, §<<, §>>, <<§
+
+
+-- | Duplicate a value and apply an arrow to the second instance.
+-- Aequivalent to
+-- > \a -> duplicate >>> second a
+-- or
+-- > \a -> returnA &&& a
+keepingTheValue :: (Arrow a) => a b c -> a b (b,c)
+keepingTheValue a = returnA &&& a
+
+-- | Duplicate a value and apply an arrow to the first instance.
+-- Aequivalent to
+-- > \a -> duplicate >>> first a
+-- or
+-- > \a -> a &&& returnA
+keepingTheValue' :: (Arrow a) => a b c -> a b (c,b)
+keepingTheValue' a = a &&& returnA
+
+-- | 'bind' from the "Maybe"-Monad lifted into an 'ArrowChoice'.
+-- Actually, it's the more complex '(>=>)', because 'bind' alone does not
+-- combine as nicely in arrow form.
+-- The current implementation is not the most efficient one, because it can
+-- not return directly if a 'Nothing' is encountered. That in turn follows
+-- from the type system, as 'Nothing' has an "invisible" type parameter that
+-- can not be dropped early.
+--
+-- Also, there probably is a way to generalize this to other monads
+-- or applicatives, but I'm leaving that as an exercise to the reader.
+-- I have a feeling there is a new Arrow-typeclass to be found that is less
+-- restrictive than 'ArrowApply'. If it is already out there,
+-- I have not seen it yet. ('ArrowPlus' for example is not general enough.)
+(>>>=) :: (ArrowChoice a) => a x (Maybe b) -> a b (Maybe c) -> a x (Maybe c)
+a1 >>>= a2 = a1 >>> maybeToChoice >>> right a2 >>> choiceToMaybe >>^ join
+
+infixr 2 >>>=
+
+-- | 'mplus' Lifted into an arrow. No 'ArrowPlus' required.
+-- (But still different from a true bind)
+(>++<) :: (Arrow a, MonadPlus m) => a x (m b) -> a x (m b) -> a x (m b)
+(>++<) = liftA2 mplus
+
+-- | Left-compose with a pure function
+leftLift :: (ArrowChoice a) => (l -> l') -> a (Either l r) (Either l' r)
+leftLift = left.arr
+
+-- | Right-compose with a pure function
+rightLift :: (ArrowChoice a) => (r -> r') -> a (Either l r) (Either l r')
+rightLift = right.arr
+
+
+( ^+++ ) :: (ArrowChoice a) => (b -> c) -> a b' c' -> a (Either b b') (Either c c')
+( +++^ ) :: (ArrowChoice a) => a b c -> (b' -> c') -> a (Either b b') (Either c c')
+( ^+++^ ) :: (ArrowChoice a) => (b -> c) -> (b' -> c') -> a (Either b b') (Either c c')
+
+l ^+++ r = leftLift l >>> right r
+l +++^ r = left l >>> rightLift r
+l ^+++^ r = leftLift l >>> rightLift r
+
+infixr 2 ^+++, +++^, ^+++^
+
+( ^||| ) :: (ArrowChoice a) => (b -> d) -> a c d -> a (Either b c) d
+( |||^ ) :: (ArrowChoice a) => a b d -> (c -> d) -> a (Either b c) d
+( ^|||^ ) :: (ArrowChoice a) => (b -> d) -> (c -> d) -> a (Either b c) d
+
+l ^||| r = arr l ||| r
+l |||^ r = l ||| arr r
+l ^|||^ r = arr l ||| arr r
+
+infixr 2 ^||| , |||^, ^|||^
+
+( ^&&& ) :: (Arrow a) => (b -> c) -> a b c' -> a b (c,c')
+( &&&^ ) :: (Arrow a) => a b c -> (b -> c') -> a b (c,c')
+( ^&&&^ ) :: (Arrow a) => (b -> c) -> (b -> c') -> a b (c,c')
+
+l ^&&& r = arr l &&& r
+l &&&^ r = l &&& arr r
+l ^&&&^ r = arr l &&& arr r
+
+infixr 3 ^&&&, &&&^, ^&&&^
+
+( ^*** ) :: (Arrow a) => (b -> c) -> a b' c' -> a (b,b') (c,c')
+( ***^ ) :: (Arrow a) => a b c -> (b' -> c') -> a (b,b') (c,c')
+( ^***^ ) :: (Arrow a) => (b -> c) -> (b' -> c') -> a (b,b') (c,c')
+
+l ^*** r = arr l *** r
+l ***^ r = l *** arr r
+l ^***^ r = arr l *** arr r
+
+infixr 3 ^***, ***^, ^***^
+
+-- | A version of
+--
+-- >>> \p -> arr (\x -> if p x the Right x else Left x)
+--
+-- but with p being an arrow
+choose :: (ArrowChoice a) => a b Bool -> a b (Either b b)
+choose checkValue = keepingTheValue checkValue >>^ select
+ where select (x,True ) = Right x
+ select (x,False ) = Left x
+
+-- | Converts @Right a@ into @Just a@ and @Left _@ into @Nothing@.
+choiceToMaybe :: (ArrowChoice a) => a (Either l r) (Maybe r)
+choiceToMaybe = arr eitherToMaybe
+
+-- | Converts @Nothing@ into @Left ()@ and @Just a@ into @Right a@.
+maybeToChoice :: (ArrowChoice a) => a (Maybe b) (Fallible b)
+maybeToChoice = arr maybeToEither
+
+-- | Lifts a constant value into an arrow
+returnV :: (Arrow a) => c -> a x c
+returnV = arr.const
+
+-- | 'returnA' dropping everything
+returnA_ :: (Arrow a) => a _b ()
+returnA_ = returnV ()
+
+-- | Wrapper for an arrow that can be evaluated im parallel. All
+-- Arrows can be evaluated in parallel, as long as they return a
+-- monoid.
+newtype ParallelArrow a b c = CoEval { evalParallelArrow :: a b c }
+ deriving (Eq, Ord, Show)
+
+instance (Arrow a, Monoid m) => Monoid (ParallelArrow a b m) where
+ mempty = CoEval $ returnV mempty
+ (CoEval a) `mappend` (CoEval ~b) = CoEval $ a &&& b >>§ mappend
+
+-- | Evaluates a collection of arrows in a parallel fashion.
+--
+-- This is in essence a fold of '(&&&)' over the collection,
+-- so the actual execution order and parallelity depends on the
+-- implementation of '(&&&)' in the arrow in question.
+-- The default implementation of '(&&&)' for example keeps the
+-- order as given in the collection.
+--
+-- This function can be seen as a generalization of
+-- 'Control.Applicative.sequenceA' to arrows or as an alternative to
+-- a fold with 'Control.Applicative.WrappedArrow', which
+-- substitutes the monoid with function application.
+--
+coEval :: (Arrow a, F.Foldable f, Monoid m) => f (a b m) -> a b m
+coEval = evalParallelArrow . (F.foldMap CoEval)
+
+-- | Defines Left as failure, Right as success
+type FallibleArrow a input failure success = a input (Either failure success)
+
+type ReFallibleArrow a failure success success'
+ = FallibleArrow a (Either failure success) failure success'
+
+-- | Wrapper for fallible arrows. Fallible arrows are all arrows that return
+-- an Either value where left is a faliure and right is a success value.
+newtype AlternativeArrow a input failure success
+ = TryArrow { evalAlternativeArrow :: FallibleArrow a input failure success }
+
+
+instance (ArrowChoice a, Monoid failure)
+ => Monoid (AlternativeArrow a input failure success) where
+ mempty = TryArrow $ returnV $ Left mempty
+ (TryArrow a) `mappend` (TryArrow b)
+ = TryArrow $ a &&& b
+ >>^ \(a',~b')
+ -> ( (\a'' -> left (mappend a'') b') ||| Right )
+ a'
+
+-- | Evaluates a collection of fallible arrows, trying each one in succession.
+-- Left values are interpreted as failures, right values as successes.
+--
+-- The evaluation is stopped once an arrow succeeds.
+-- Up to that point, all failures are collected in the failure-monoid.
+-- Note that '()' is a monoid, and thus can serve as a failure-collector if
+-- you are uninterested in the exact failures.
+--
+-- This is in essence a fold of '(&&&)' over the collection, enhanced with a
+-- little bit of repackaging, so the actual execution order depends on the
+-- implementation of '(&&&)' in the arrow in question.
+-- The default implementation of '(&&&)' for example keeps the
+-- order as given in the collection.
+--
+tryArrows :: (ArrowChoice a, F.Foldable f, Monoid failure)
+ => f (FallibleArrow a b failure success)
+ -> FallibleArrow a b failure success
+tryArrows = evalAlternativeArrow . (F.foldMap TryArrow)
+
+--
+liftSuccess :: (ArrowChoice a)
+ => (success -> success')
+ -> ReFallibleArrow a failure success success'
+liftSuccess = rightLift
+
+--
+liftAsSuccess :: (ArrowChoice a)
+ => a x success
+ -> FallibleArrow a x failure success
+liftAsSuccess a = a >>^ Right
+
+--
+asFallibleArrow :: (ArrowChoice a)
+ => a x success
+ -> FallibleArrow a x failure success
+asFallibleArrow a = a >>^ Right
+
+-- | Raises an error into a 'ReFallibleArrow' if the arrow is already in
+-- "error mode"
+liftError :: (ArrowChoice a, Monoid failure)
+ => failure
+ -> ReFallibleArrow a failure success success
+liftError e = leftLift (e <>)
+
+-- | Raises an error into a 'FallibleArrow', droping both the arrow input
+-- and any previously stored error value.
+_raiseA :: (ArrowChoice a)
+ => failure
+ -> FallibleArrow a x failure success
+_raiseA e = returnV (Left e)
+
+-- | Raises an empty error into a 'FallibleArrow', droping both the arrow input
+-- and any previously stored error value.
+_raiseAEmpty :: (ArrowChoice a, Monoid failure)
+ => FallibleArrow a x failure success
+_raiseAEmpty = _raiseA mempty
+
+-- | Raises an error into a 'ReFallibleArrow', possibly appending the new error
+-- to an existing one
+raiseA :: (ArrowChoice a, Monoid failure)
+ => failure
+ -> ReFallibleArrow a failure success success
+raiseA e = arr $ Left.(either (<> e) (const e))
+
+-- | Raises an empty error into a 'ReFallibleArrow'. If there already is an
+-- error, nothing changes.
+-- (Note that this function is only aequivalent to @raiseA mempty@ iff the
+-- failure monoid follows the monoid laws.)
+raiseAEmpty :: (ArrowChoice a, Monoid failure)
+ => ReFallibleArrow a failure success success
+raiseAEmpty = arr (fromRight (const mempty) >>> Left)
+
+
+-- | Execute the second arrow if the first succeeds
+(>>?) :: (ArrowChoice a, Monoid failure)
+ => FallibleArrow a x failure success
+ -> FallibleArrow a success failure success'
+ -> FallibleArrow a x failure success'
+a >>? b = a >>> Left ^||| b
+
+-- | Execute the lifted second arrow if the first succeeds
+(>>?^) :: (ArrowChoice a, Monoid failure)
+ => FallibleArrow a x failure success
+ -> (success -> success')
+ -> FallibleArrow a x failure success'
+a >>?^ f = a >>^ Left ^|||^ Right . f
+
+-- | Execute the lifted second arrow if the first succeeds
+(>>?^?) :: (ArrowChoice a, Monoid failure)
+ => FallibleArrow a x failure success
+ -> (success -> Either failure success')
+ -> FallibleArrow a x failure success'
+a >>?^? b = a >>> Left ^|||^ b
+
+-- | Execute the second arrow if the lifted first arrow succeeds
+(^>>?) :: (ArrowChoice a, Monoid failure)
+ => (x -> Either failure success)
+ -> FallibleArrow a success failure success'
+ -> FallibleArrow a x failure success'
+a ^>>? b = a ^>> Left ^||| b
+
+-- | Execute the lifted second arrow if the lifted first arrow succeeds
+(^>>?^) :: (ArrowChoice a, Monoid failure)
+ => (x -> Either failure success)
+ -> (success -> success')
+ -> FallibleArrow a x failure success'
+a ^>>?^ f = arr $ a >>> right f
+
+-- | Execute the lifted second arrow if the lifted first arrow succeeds
+(^>>?^?) :: (ArrowChoice a, Monoid failure)
+ => (x -> Either failure success)
+ -> (success -> Either failure success')
+ -> FallibleArrow a x failure success'
+a ^>>?^? f = a ^>> Left ^|||^ f
+
+-- | Execute the second, non-fallible arrow if the first arrow succeeds
+(>>?!) :: (ArrowChoice a, Monoid failure)
+ => FallibleArrow a x failure success
+ -> a success success'
+ -> FallibleArrow a x failure success'
+a >>?! f = a >>> right f
+
+---
+(>>?§) :: (ArrowChoice a, Monoid f)
+ => FallibleArrow a x f (b,b')
+ -> (b -> b' -> c)
+ -> FallibleArrow a x f c
+a >>?§ f = a >>?^ (uncurry f)
+
+---
+(^>>?§) :: (ArrowChoice a, Monoid f)
+ => (x -> Either f (b,b'))
+ -> (b -> b' -> c)
+ -> FallibleArrow a x f c
+a ^>>?§ f = arr a >>?^ (uncurry f)
+
+---
+(>>?§?) :: (ArrowChoice a, Monoid f)
+ => FallibleArrow a x f (b,b')
+ -> (b -> b' -> (Either f c))
+ -> FallibleArrow a x f c
+a >>?§? f = a >>?^? (uncurry f)
+
+infixr 1 >>?, >>?^, >>?^?
+infixr 1 ^>>?, ^>>?^, ^>>?^?, >>?!
+infixr 1 >>?§, ^>>?§, >>?§?
+
+-- | Keep values that are Right, replace Left values by a constant.
+ifFailedUse :: (ArrowChoice a) => v -> a (Either f v) v
+ifFailedUse v = arr $ either (const v) id
+
+-- | '(&&)' lifted into an arrow
+(<&&>) :: (Arrow a) => a x Bool -> a x Bool -> a x Bool
+(<&&>) = liftA2 (&&)
+
+-- | '(||)' lifted into an arrow
+(<||>) :: (Arrow a) => a x Bool -> a x Bool -> a x Bool
+(<||>) = liftA2 (||)
+
+-- | An equivalent of '(&&)' in a fallible arrow
+(>&&<) :: (ArrowChoice a, Monoid f) => FallibleArrow a x f s
+ -> FallibleArrow a x f s'
+ -> FallibleArrow a x f (s,s')
+(>&&<) = liftA2 chooseMin
+
+-- | An equivalent of '(||)' in some forms of fallible arrows
+(>||<) :: (ArrowChoice a, Monoid f, Monoid s) => FallibleArrow a x f s
+ -> FallibleArrow a x f s
+ -> FallibleArrow a x f s
+(>||<) = liftA2 chooseMax
+
+-- | An arrow version of a short-circuit (<|>)
+ifFailedDo :: (ArrowChoice a)
+ => FallibleArrow a x f y
+ -> FallibleArrow a x f y
+ -> FallibleArrow a x f y
+ifFailedDo a b = keepingTheValue a >>> repackage ^>> (b |||^ Right)
+ where repackage (x , Left _) = Left x
+ repackage (_ , Right y) = Right y
+
+infixr 4 <&&>, <||>, >&&<, >||<
+infixr 1 `ifFailedDo`
+
+
diff --git a/src/Text/Pandoc/Readers/Odt/Base.hs b/src/Text/Pandoc/Readers/Odt/Base.hs
new file mode 100644
index 000000000..1f095bade
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Base.hs
@@ -0,0 +1,43 @@
+{-# LANGUAGE PatternGuards #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Base
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Core types of the odt reader.
+-}
+
+module Text.Pandoc.Readers.Odt.Base where
+
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Readers.Odt.Namespaces
+
+type OdtConverterState s = XMLConverterState Namespace s
+
+type XMLReader s a b = FallibleXMLConverter Namespace s a b
+
+type XMLReaderSafe s a b = XMLConverter Namespace s a b
+
diff --git a/src/Text/Pandoc/Readers/Odt/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
new file mode 100644
index 000000000..9bb585b8e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -0,0 +1,790 @@
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.ContentReader
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+The core of the odt reader that converts odt features into Pandoc types.
+-}
+
+module Text.Pandoc.Readers.Odt.ContentReader
+( readerState
+, read_body
+) where
+
+import Control.Arrow
+import Control.Applicative hiding ( liftA, liftA2, liftA3 )
+
+import qualified Data.Map as M
+import Data.List ( find )
+import Data.Monoid
+import Data.Maybe
+
+import qualified Text.XML.Light as XML
+
+import Text.Pandoc.Definition
+import Text.Pandoc.Builder
+import Text.Pandoc.Shared
+
+import Text.Pandoc.Readers.Odt.Base
+import Text.Pandoc.Readers.Odt.Namespaces
+import Text.Pandoc.Readers.Odt.StyleReader
+
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.Utils
+
+
+--------------------------------------------------------------------------------
+-- State
+--------------------------------------------------------------------------------
+
+type Anchor = String
+
+data ReaderState
+ = ReaderState { -- | A collection of styles read somewhere else.
+ -- It is only queried here, not modified.
+ styleSet :: Styles
+ -- | A stack of the styles of parent elements.
+ -- Used to look up inherited style properties.
+ , styleTrace :: [Style]
+ -- | Keeps track of the current depth in nested lists
+ , currentListLevel :: ListLevel
+ -- | Lists may provide their own style, but they don't have
+ -- to. If they do not, the style of a parent list may be used
+ -- or even a default list style from the paragraph style.
+ -- This value keeps track of the closest list style there
+ -- currently is.
+ , currentListStyle :: Maybe ListStyle
+ -- | A map from internal anchor names to "pretty" ones.
+ -- The mapping is a purely cosmetic one.
+ , bookmarkAnchors :: M.Map Anchor Anchor
+
+-- , sequences
+-- , trackedChangeIDs
+ }
+ deriving ( Show )
+
+readerState :: Styles -> ReaderState
+readerState styles = ReaderState styles [] 0 Nothing M.empty
+
+--
+pushStyle' :: Style -> ReaderState -> ReaderState
+pushStyle' style state = state { styleTrace = style : styleTrace state }
+
+--
+popStyle' :: ReaderState -> ReaderState
+popStyle' state = case styleTrace state of
+ _:trace -> state { styleTrace = trace }
+ _ -> state
+
+--
+modifyListLevel :: (ListLevel -> ListLevel) -> (ReaderState -> ReaderState)
+modifyListLevel f state = state { currentListLevel = f (currentListLevel state) }
+
+--
+shiftListLevel :: ListLevel -> (ReaderState -> ReaderState)
+shiftListLevel diff = modifyListLevel (+ diff)
+
+--
+swapCurrentListStyle :: Maybe ListStyle -> ReaderState
+ -> (ReaderState, Maybe ListStyle)
+swapCurrentListStyle mListStyle state = ( state { currentListStyle = mListStyle }
+ , currentListStyle state
+ )
+
+--
+lookupPrettyAnchor :: Anchor -> ReaderState -> Maybe Anchor
+lookupPrettyAnchor anchor ReaderState{..} = M.lookup anchor bookmarkAnchors
+
+--
+putPrettyAnchor :: Anchor -> Anchor -> ReaderState -> ReaderState
+putPrettyAnchor ugly pretty state@ReaderState{..}
+ = state { bookmarkAnchors = M.insert ugly pretty bookmarkAnchors }
+
+--
+usedAnchors :: ReaderState -> [Anchor]
+usedAnchors ReaderState{..} = M.elems bookmarkAnchors
+
+--------------------------------------------------------------------------------
+-- Reader type and associated tools
+--------------------------------------------------------------------------------
+
+type OdtReader a b = XMLReader ReaderState a b
+
+type OdtReaderSafe a b = XMLReaderSafe ReaderState a b
+
+-- | Extract something from the styles
+fromStyles :: (a -> Styles -> b) -> OdtReaderSafe a b
+fromStyles f = keepingTheValue
+ (getExtraState >>^ styleSet)
+ >>§ f
+
+--
+getStyleByName :: OdtReader StyleName Style
+getStyleByName = fromStyles lookupStyle >>^ maybeToChoice
+
+--
+findStyleFamily :: OdtReader Style StyleFamily
+findStyleFamily = fromStyles getStyleFamily >>^ maybeToChoice
+
+--
+lookupListStyle :: OdtReader StyleName ListStyle
+lookupListStyle = fromStyles lookupListStyleByName >>^ maybeToChoice
+
+--
+switchCurrentListStyle :: OdtReaderSafe (Maybe ListStyle) (Maybe ListStyle)
+switchCurrentListStyle = keepingTheValue getExtraState
+ >>§ swapCurrentListStyle
+ >>> first setExtraState
+ >>^ snd
+
+--
+pushStyle :: OdtReaderSafe Style Style
+pushStyle = keepingTheValue (
+ ( keepingTheValue getExtraState
+ >>§ pushStyle'
+ )
+ >>> setExtraState
+ )
+ >>^ fst
+
+--
+popStyle :: OdtReaderSafe x x
+popStyle = keepingTheValue (
+ getExtraState
+ >>> arr popStyle'
+ >>> setExtraState
+ )
+ >>^ fst
+
+--
+getCurrentListLevel :: OdtReaderSafe _x ListLevel
+getCurrentListLevel = getExtraState >>^ currentListLevel
+
+
+type AnchorPrefix = String
+
+-- | An adaptation of 'uniqueIdent' from "Text.Pandoc.Shared" that generates a
+-- unique identifier but without assuming that the id should be for a header.
+-- Second argument is a list of already used identifiers.
+uniqueIdentFrom :: AnchorPrefix -> [Anchor] -> Anchor
+uniqueIdentFrom baseIdent usedIdents =
+ let numIdent n = baseIdent ++ "-" ++ show n
+ in if baseIdent `elem` usedIdents
+ then case find (\x -> numIdent x `notElem` usedIdents) ([1..60000] :: [Int]) of
+ Just x -> numIdent x
+ Nothing -> baseIdent -- if we have more than 60,000, allow repeats
+ else baseIdent
+
+-- | First argument: basis for a new "pretty" anchor if none exists yet
+-- Second argument: a key ("ugly" anchor)
+-- Returns: saved "pretty" anchor or created new one
+getPrettyAnchor :: OdtReaderSafe (AnchorPrefix, Anchor) Anchor
+getPrettyAnchor = proc (baseIdent, uglyAnchor) -> do
+ state <- getExtraState -< ()
+ case lookupPrettyAnchor uglyAnchor state of
+ Just prettyAnchor -> returnA -< prettyAnchor
+ Nothing -> do
+ let newPretty = uniqueIdentFrom baseIdent (usedAnchors state)
+ modifyExtraState (putPrettyAnchor uglyAnchor newPretty) -<< newPretty
+
+-- | Input: basis for a new header anchor
+-- Ouput: saved new anchor
+getHeaderAnchor :: OdtReaderSafe Inlines Anchor
+getHeaderAnchor = proc title -> do
+ state <- getExtraState -< ()
+ let anchor = uniqueIdent (toList title) (usedAnchors state)
+ modifyExtraState (putPrettyAnchor anchor anchor) -<< anchor
+
+
+--------------------------------------------------------------------------------
+-- Working with styles
+--------------------------------------------------------------------------------
+
+--
+readStyleByName :: OdtReader _x Style
+readStyleByName = findAttr NsText "style-name" >>? getStyleByName
+
+--
+isStyleToTrace :: OdtReader Style Bool
+isStyleToTrace = findStyleFamily >>?^ (==FaText)
+
+--
+withNewStyle :: OdtReaderSafe x Inlines -> OdtReaderSafe x Inlines
+withNewStyle a = proc x -> do
+ fStyle <- readStyleByName -< ()
+ case fStyle of
+ Right style -> do
+ mFamily <- arr styleFamily -< style
+ fTextProps <- arr ( maybeToChoice
+ . textProperties
+ . styleProperties
+ ) -< style
+ case fTextProps of
+ Right textProps -> do
+ state <- getExtraState -< ()
+ let triple = (state, textProps, mFamily)
+ modifier <- arr modifierFromStyleDiff -< triple
+ fShouldTrace <- isStyleToTrace -< style
+ case fShouldTrace of
+ Right shouldTrace -> do
+ if shouldTrace
+ then do
+ pushStyle -< style
+ inlines <- a -< x
+ popStyle -< ()
+ arr modifier -<< inlines
+ else
+ -- In case anything goes wrong
+ a -< x
+ Left _ -> a -< x
+ Left _ -> a -< x
+ Left _ -> a -< x
+
+
+type PropertyTriple = (ReaderState, TextProperties, Maybe StyleFamily)
+type InlineModifier = Inlines -> Inlines
+
+-- | Given data about the local style changes, calculates how to modify
+-- an instance of 'Inlines'
+modifierFromStyleDiff :: PropertyTriple -> InlineModifier
+modifierFromStyleDiff propertyTriple =
+ composition $
+ (getVPosModifier propertyTriple)
+ : map (first ($ propertyTriple) >>> ifThen_else ignore)
+ [ (hasEmphChanged , emph )
+ , (hasChanged isStrong , strong )
+ , (hasChanged strikethrough , strikeout )
+ ]
+ where
+ ifThen_else else' (if',then') = if if' then then' else else'
+
+ ignore = id :: InlineModifier
+
+ getVPosModifier :: PropertyTriple -> InlineModifier
+ getVPosModifier triple@(_,textProps,_) =
+ let getVPos = Just . verticalPosition
+ in case lookupPreviousValueM getVPos triple of
+ Nothing -> ignore
+ Just oldVPos -> getVPosModifier' (oldVPos,verticalPosition textProps)
+
+ getVPosModifier' (oldVPos , newVPos ) | oldVPos == newVPos = ignore
+ getVPosModifier' ( _ , VPosSub ) = subscript
+ getVPosModifier' ( _ , VPosSuper ) = superscript
+ getVPosModifier' ( _ , _ ) = ignore
+
+ hasEmphChanged :: PropertyTriple -> Bool
+ hasEmphChanged = swing any [ hasChanged isEmphasised
+ , hasChangedM pitch
+ , hasChanged underline
+ ]
+
+ hasChanged property triple@(_, property -> newProperty, _) =
+ maybe True (/=newProperty) (lookupPreviousValue property triple)
+
+ hasChangedM property triple@(_, textProps,_) =
+ fromMaybe False $ (/=) <$> property textProps <*> lookupPreviousValueM property triple
+
+ lookupPreviousValue f = lookupPreviousStyleValue ((fmap f).textProperties)
+
+ lookupPreviousValueM f = lookupPreviousStyleValue ((f =<<).textProperties)
+
+ lookupPreviousStyleValue f (ReaderState{..},_,mFamily)
+ = ( findBy f $ extendedStylePropertyChain styleTrace styleSet )
+ <|> ( f =<< fmap (lookupDefaultStyle' styleSet) mFamily )
+
+
+type ParaModifier = Blocks -> Blocks
+
+_MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_MM_ :: Int
+_MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_PERCENT_ :: Int
+_MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_MM_ = 5
+_MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_PERCENT_ = 5
+
+-- | Returns either 'id' or 'blockQuote' depending on the current indentation
+getParaModifier :: Style -> ParaModifier
+getParaModifier Style{..} | Just props <- paraProperties styleProperties
+ , isBlockQuote (indentation props)
+ (margin_left props)
+ = blockQuote
+ | otherwise
+ = id
+ where
+ isBlockQuote mIndent mMargin
+ | LengthValueMM indent <- mIndent
+ , indent > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_MM_
+ = True
+ | LengthValueMM margin <- mMargin
+ , margin > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_MM_
+ = True
+ | LengthValueMM indent <- mIndent
+ , LengthValueMM margin <- mMargin
+ = indent + margin > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_MM_
+
+ | PercentValue indent <- mIndent
+ , indent > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_PERCENT_
+ = True
+ | PercentValue margin <- mMargin
+ , margin > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_PERCENT_
+ = True
+ | PercentValue indent <- mIndent
+ , PercentValue margin <- mMargin
+ = indent + margin > _MINIMUM_INDENTATION_FOR_BLOCKQUOTES_IN_PERCENT_
+
+ | otherwise
+ = False
+
+--
+constructPara :: OdtReaderSafe Blocks Blocks -> OdtReaderSafe Blocks Blocks
+constructPara reader = proc blocks -> do
+ fStyle <- readStyleByName -< blocks
+ case fStyle of
+ Left _ -> reader -< blocks
+ Right style -> do
+ let modifier = getParaModifier style
+ blocks' <- reader -< blocks
+ arr modifier -<< blocks'
+
+
+
+type ListConstructor = [Blocks] -> Blocks
+
+getListConstructor :: ListLevelStyle -> ListConstructor
+getListConstructor ListLevelStyle{..} =
+ case listLevelType of
+ LltBullet -> bulletList
+ LltImage -> bulletList
+ LltNumbered -> let listNumberStyle = toListNumberStyle listItemFormat
+ listNumberDelim = toListNumberDelim listItemPrefix
+ listItemSuffix
+ in orderedListWith (1, listNumberStyle, listNumberDelim)
+ where
+ toListNumberStyle LinfNone = DefaultStyle
+ toListNumberStyle LinfNumber = Decimal
+ toListNumberStyle LinfRomanLC = LowerRoman
+ toListNumberStyle LinfRomanUC = UpperRoman
+ toListNumberStyle LinfAlphaLC = LowerAlpha
+ toListNumberStyle LinfAlphaUC = UpperAlpha
+ toListNumberStyle (LinfString _) = Example
+
+ toListNumberDelim Nothing (Just ".") = Period
+ toListNumberDelim (Just "" ) (Just ".") = Period
+ toListNumberDelim Nothing (Just ")") = OneParen
+ toListNumberDelim (Just "" ) (Just ")") = OneParen
+ toListNumberDelim (Just "(") (Just ")") = TwoParens
+ toListNumberDelim _ _ = DefaultDelim
+
+
+-- | Determines which style to use for a list, which level to use of that
+-- style, and which type of list to create as a result of this information.
+-- Then prepares the state for eventual child lists and constructs the list from
+-- the results.
+-- Two main cases are handled: The list may provide its own style or it may
+-- rely on a parent list's style. I the former case the current style in the
+-- state must be switched before and after the call to the child converter
+-- while in the latter the child converter can be called directly.
+-- If anything goes wrong, a default ordered-list-constructor is used.
+constructList :: OdtReaderSafe x [Blocks] -> OdtReaderSafe x Blocks
+constructList reader = proc x -> do
+ modifyExtraState (shiftListLevel 1) -< ()
+ listLevel <- getCurrentListLevel -< ()
+ fStyleName <- findAttr NsText "style-name" -< ()
+ case fStyleName of
+ Right styleName -> do
+ fListStyle <- lookupListStyle -< styleName
+ case fListStyle of
+ Right listStyle -> do
+ fLLS <- arr (uncurry getListLevelStyle) -< (listLevel,listStyle)
+ case fLLS of
+ Just listLevelStyle -> do
+ oldListStyle <- switchCurrentListStyle -< Just listStyle
+ blocks <- constructListWith listLevelStyle -<< x
+ switchCurrentListStyle -< oldListStyle
+ returnA -< blocks
+ Nothing -> constructOrderedList -< x
+ Left _ -> constructOrderedList -< x
+ Left _ -> do
+ state <- getExtraState -< ()
+ mListStyle <- arr currentListStyle -< state
+ case mListStyle of
+ Just listStyle -> do
+ fLLS <- arr (uncurry getListLevelStyle) -< (listLevel,listStyle)
+ case fLLS of
+ Just listLevelStyle -> constructListWith listLevelStyle -<< x
+ Nothing -> constructOrderedList -< x
+ Nothing -> constructOrderedList -< x
+ where
+ constructOrderedList =
+ reader
+ >>> modifyExtraState (shiftListLevel (-1))
+ >>^ orderedList
+ constructListWith listLevelStyle =
+ reader
+ >>> getListConstructor listLevelStyle
+ ^>> modifyExtraState (shiftListLevel (-1))
+
+--------------------------------------------------------------------------------
+-- Readers
+--------------------------------------------------------------------------------
+
+type ElementMatcher result = (Namespace, ElementName, OdtReader result result)
+
+type InlineMatcher = ElementMatcher Inlines
+
+type BlockMatcher = ElementMatcher Blocks
+
+
+--
+matchingElement :: (Monoid e)
+ => Namespace -> ElementName
+ -> OdtReaderSafe e e
+ -> ElementMatcher e
+matchingElement ns name reader = (ns, name, asResultAccumulator reader)
+ where
+ asResultAccumulator :: (ArrowChoice a, Monoid m) => a m m -> a m (Fallible m)
+ asResultAccumulator a = liftAsSuccess $ keepingTheValue a >>§ (<>)
+
+--
+matchChildContent' :: (Monoid result)
+ => [ElementMatcher result]
+ -> OdtReaderSafe _x result
+matchChildContent' ls = returnV mempty >>> matchContent' ls
+
+--
+matchChildContent :: (Monoid result)
+ => [ElementMatcher result]
+ -> OdtReaderSafe (result, XML.Content) result
+ -> OdtReaderSafe _x result
+matchChildContent ls fallback = returnV mempty >>> matchContent ls fallback
+
+
+--------------------------------------------
+-- Matchers
+--------------------------------------------
+
+----------------------
+-- Basics
+----------------------
+
+--
+-- | Open Document allows several consecutive spaces if they are marked up
+read_plain_text :: OdtReaderSafe (Inlines, XML.Content) Inlines
+read_plain_text = fst ^&&& read_plain_text' >>§ recover
+ where
+ -- fallible version
+ read_plain_text' :: OdtReader (Inlines, XML.Content) Inlines
+ read_plain_text' = ( second ( arr extractText )
+ >>^ spreadChoice >>?! second text
+ )
+ >>?§ (<>)
+ --
+ extractText :: XML.Content -> Fallible String
+ extractText (XML.Text cData) = succeedWith (XML.cdData cData)
+ extractText _ = failEmpty
+
+
+-- specifically. I honor that, although the current implementation of '(<>)'
+-- for 'Inlines' in "Text.Pandoc.Builder" will collaps them agein.
+-- The rational is to be prepared for future modifications.
+read_spaces :: InlineMatcher
+read_spaces = matchingElement NsText "s" (
+ readAttrWithDefault NsText "c" 1 -- how many spaces?
+ >>^ fromList.(`replicate` Space)
+ )
+--
+read_line_break :: InlineMatcher
+read_line_break = matchingElement NsText "line-break"
+ $ returnV linebreak
+
+--
+read_span :: InlineMatcher
+read_span = matchingElement NsText "span"
+ $ withNewStyle
+ $ matchChildContent [ read_span
+ , read_spaces
+ , read_line_break
+ , read_link
+ , read_note
+ , read_citation
+ , read_bookmark
+ , read_bookmark_start
+ , read_reference_start
+ , read_bookmark_ref
+ , read_reference_ref
+ ] read_plain_text
+
+--
+read_paragraph :: BlockMatcher
+read_paragraph = matchingElement NsText "p"
+ $ constructPara
+ $ liftA para
+ $ withNewStyle
+ $ matchChildContent [ read_span
+ , read_spaces
+ , read_line_break
+ , read_link
+ , read_note
+ , read_citation
+ , read_bookmark
+ , read_bookmark_start
+ , read_reference_start
+ , read_bookmark_ref
+ , read_reference_ref
+ ] read_plain_text
+
+
+----------------------
+-- Headers
+----------------------
+
+--
+read_header :: BlockMatcher
+read_header = matchingElement NsText "h"
+ $ proc blocks -> do
+ level <- ( readAttrWithDefault NsText "outline-level" 1
+ ) -< blocks
+ children <- ( matchChildContent [ read_span
+ , read_spaces
+ , read_line_break
+ , read_link
+ , read_note
+ , read_citation
+ , read_bookmark
+ , read_bookmark_start
+ , read_reference_start
+ , read_bookmark_ref
+ , read_reference_ref
+ ] read_plain_text
+ ) -< blocks
+ anchor <- getHeaderAnchor -< children
+ let idAttr = (anchor, [], []) -- no classes, no key-value pairs
+ arr (uncurry3 headerWith) -< (idAttr, level, children)
+
+----------------------
+-- Lists
+----------------------
+
+--
+read_list :: BlockMatcher
+read_list = matchingElement NsText "list"
+-- $ withIncreasedListLevel
+ $ constructList
+-- $ liftA bulletList
+ $ matchChildContent' [ read_list_item
+ ]
+--
+read_list_item :: ElementMatcher [Blocks]
+read_list_item = matchingElement NsText "list-item"
+ $ liftA (compactify'.(:[]))
+ ( matchChildContent' [ read_paragraph
+ , read_header
+ , read_list
+ ]
+ )
+
+
+----------------------
+-- Links
+----------------------
+
+read_link :: InlineMatcher
+read_link = matchingElement NsText "a"
+ $ liftA3 link
+ ( findAttrWithDefault NsXLink "href" "" )
+ ( findAttrWithDefault NsOffice "title" "" )
+ ( matchChildContent [ read_span
+ , read_note
+ , read_citation
+ , read_bookmark
+ , read_bookmark_start
+ , read_reference_start
+ , read_bookmark_ref
+ , read_reference_ref
+ ] read_plain_text )
+
+
+-------------------------
+-- Footnotes
+-------------------------
+
+read_note :: InlineMatcher
+read_note = matchingElement NsText "note"
+ $ liftA note
+ $ matchChildContent' [ read_note_body ]
+
+read_note_body :: BlockMatcher
+read_note_body = matchingElement NsText "note-body"
+ $ matchChildContent' [ read_paragraph ]
+
+-------------------------
+-- Citations
+-------------------------
+
+read_citation :: InlineMatcher
+read_citation = matchingElement NsText "bibliography-mark"
+ $ liftA2 cite
+ ( liftA2 makeCitation
+ ( findAttrWithDefault NsText "identifier" "" )
+ ( readAttrWithDefault NsText "number" 0 )
+ )
+ ( matchChildContent [] read_plain_text )
+ where
+ makeCitation :: String -> Int -> [Citation]
+ makeCitation citeId num = [Citation citeId [] [] NormalCitation num 0]
+
+
+----------------------
+-- Tables
+----------------------
+
+--
+read_table :: BlockMatcher
+read_table = matchingElement NsTable "table"
+ $ liftA (simpleTable [])
+ $ matchChildContent' [ read_table_row
+ ]
+
+--
+read_table_row :: ElementMatcher [[Blocks]]
+read_table_row = matchingElement NsTable "table-row"
+ $ liftA (:[])
+ $ matchChildContent' [ read_table_cell
+ ]
+
+--
+read_table_cell :: ElementMatcher [Blocks]
+read_table_cell = matchingElement NsTable "table-cell"
+ $ liftA (compactify'.(:[]))
+ $ matchChildContent' [ read_paragraph
+ ]
+
+----------------------
+-- Internal links
+----------------------
+
+_ANCHOR_PREFIX_ :: String
+_ANCHOR_PREFIX_ = "anchor"
+
+--
+readAnchorAttr :: OdtReader _x Anchor
+readAnchorAttr = findAttr NsText "name"
+
+-- | Beware: may fail
+findAnchorName :: OdtReader AnchorPrefix Anchor
+findAnchorName = ( keepingTheValue readAnchorAttr
+ >>^ spreadChoice
+ ) >>?! getPrettyAnchor
+
+
+--
+maybeAddAnchorFrom :: OdtReader Inlines AnchorPrefix
+ -> OdtReaderSafe Inlines Inlines
+maybeAddAnchorFrom anchorReader =
+ keepingTheValue (anchorReader >>? findAnchorName >>?^ toAnchorElem)
+ >>>
+ proc (inlines, fAnchorElem) -> do
+ case fAnchorElem of
+ Right anchorElem ->
+ arr (anchorElem <>) -<< inlines
+ Left _ -> returnA -< inlines
+ where
+ toAnchorElem :: Anchor -> Inlines
+ toAnchorElem anchorID = spanWith (anchorID, [], []) mempty
+ -- no classes, no key-value pairs
+
+--
+read_bookmark :: InlineMatcher
+read_bookmark = matchingElement NsText "bookmark"
+ $ maybeAddAnchorFrom (liftAsSuccess $ returnV _ANCHOR_PREFIX_)
+
+--
+read_bookmark_start :: InlineMatcher
+read_bookmark_start = matchingElement NsText "bookmark-start"
+ $ maybeAddAnchorFrom (liftAsSuccess $ returnV _ANCHOR_PREFIX_)
+
+--
+read_reference_start :: InlineMatcher
+read_reference_start = matchingElement NsText "reference-mark-start"
+ $ maybeAddAnchorFrom readAnchorAttr
+
+-- | Beware: may fail
+findAnchorRef :: OdtReader _x Anchor
+findAnchorRef = ( findAttr NsText "ref-name"
+ >>?^ (_ANCHOR_PREFIX_,)
+ ) >>?! getPrettyAnchor
+
+
+--
+maybeInAnchorRef :: OdtReaderSafe Inlines Inlines
+maybeInAnchorRef = proc inlines -> do
+ fRef <- findAnchorRef -< ()
+ case fRef of
+ Right anchor ->
+ arr (toAnchorRef anchor) -<< inlines
+ Left _ -> returnA -< inlines
+ where
+ toAnchorRef :: Anchor -> Inlines -> Inlines
+ toAnchorRef anchor = link ('#':anchor) "" -- no title
+
+--
+read_bookmark_ref :: InlineMatcher
+read_bookmark_ref = matchingElement NsText "bookmark-ref"
+ $ maybeInAnchorRef
+ <<< matchChildContent [] read_plain_text
+
+--
+read_reference_ref :: InlineMatcher
+read_reference_ref = matchingElement NsText "reference-ref"
+ $ maybeInAnchorRef
+ <<< matchChildContent [] read_plain_text
+
+
+----------------------
+-- Entry point
+----------------------
+
+--read_plain_content :: OdtReaderSafe _x Inlines
+--read_plain_content = strContent >>^ text
+
+read_text :: OdtReaderSafe _x Pandoc
+read_text = matchChildContent' [ read_header
+ , read_paragraph
+ , read_list
+ , read_table
+ ]
+ >>^ doc
+
+read_body :: OdtReader _x Pandoc
+read_body = executeIn NsOffice "body"
+ $ executeIn NsOffice "text"
+ $ liftAsSuccess read_text
+
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
new file mode 100644
index 000000000..5922164c9
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
@@ -0,0 +1,260 @@
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Generic.Fallible
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Data types and utilities representing failure. Most of it is based on the
+"Either" type in its usual configuration (left represents failure).
+
+In most cases, the failure type is implied or required to be a "Monoid".
+
+The choice of "Either" instead of a custom type makes it easier to write
+compatible instances of "ArrowChoice".
+-}
+
+-- We export everything
+module Text.Pandoc.Readers.Odt.Generic.Fallible where
+
+import Control.Applicative
+import Control.Monad
+
+import qualified Data.Foldable as F
+import Data.Monoid
+
+-- | Default for now. Will probably become a class at some point.
+type Failure = ()
+
+type Fallible a = Either Failure a
+
+
+-- | False -> Left (), True -> Right ()
+boolToEither :: Bool -> Fallible ()
+boolToEither False = Left ()
+boolToEither True = Right ()
+
+-- | False -> Left (), True -> Right ()
+boolToChoice :: Bool -> Fallible ()
+boolToChoice False = Left ()
+boolToChoice True = Right ()
+
+--
+maybeToEither :: Maybe a -> Fallible a
+maybeToEither (Just a) = Right a
+maybeToEither Nothing = Left ()
+
+--
+eitherToMaybe :: Either _l a -> Maybe a
+eitherToMaybe (Left _) = Nothing
+eitherToMaybe (Right a) = Just a
+
+-- | > untagEither === either id id
+untagEither :: Either a a -> a
+untagEither (Left a) = a
+untagEither (Right a) = a
+
+-- | > fromLeft f === either f id
+fromLeft :: (a -> b) -> Either a b -> b
+fromLeft f (Left a) = f a
+fromLeft _ (Right b) = b
+
+-- | > fromRight f === either id f
+fromRight :: (a -> b) -> Either b a -> b
+fromRight _ (Left b) = b
+fromRight f (Right a) = f a
+
+-- | > recover a === fromLeft (const a) === either (const a) id
+recover :: a -> Either _f a -> a
+recover a (Left _) = a
+recover _ (Right a) = a
+
+-- | I would love to use 'fail'. Alas, 'Monad.fail'...
+failWith :: failure -> Either failure _x
+failWith f = Left f
+
+--
+failEmpty :: (Monoid failure) => Either failure _x
+failEmpty = failWith mempty
+
+--
+succeedWith :: a -> Either _x a
+succeedWith = Right
+
+--
+collapseEither :: Either failure (Either failure x)
+ -> Either failure x
+collapseEither (Left f ) = Left f
+collapseEither (Right (Left f)) = Left f
+collapseEither (Right (Right x)) = Right x
+
+-- | If either of the values represents an error, the result is a
+-- (possibly combined) error. If both values represent a success,
+-- both are returned.
+chooseMin :: (Monoid a) => Either a b -> Either a b' -> Either a (b,b')
+chooseMin = chooseMinWith (,)
+
+-- | If either of the values represents an error, the result is a
+-- (possibly combined) error. If both values represent a success,
+-- a combination is returned.
+chooseMinWith :: (Monoid a) => (b -> b' -> c)
+ -> Either a b
+ -> Either a b'
+ -> Either a c
+chooseMinWith (><) (Right a) (Right b) = Right $ a >< b
+chooseMinWith _ (Left a) (Left b) = Left $ a <> b
+chooseMinWith _ (Left a) _ = Left a
+chooseMinWith _ _ (Left b) = Left b
+
+-- | If either of the values represents a non-error, the result is a
+-- (possibly combined) non-error. If both values represent an error, an error
+-- is returned.
+chooseMax :: (Monoid a, Monoid b) => Either a b -> Either a b -> Either a b
+chooseMax = chooseMaxWith (<>)
+
+-- | If either of the values represents a non-error, the result is a
+-- (possibly combined) non-error. If both values represent an error, an error
+-- is returned.
+chooseMaxWith :: (Monoid a) => (b -> b -> b)
+ -> Either a b
+ -> Either a b
+ -> Either a b
+chooseMaxWith (><) (Right a) (Right b) = Right $ a >< b
+chooseMaxWith _ (Left a) (Left b) = Left $ a <> b
+chooseMaxWith _ (Right a) _ = Right a
+chooseMaxWith _ _ (Right b) = Right b
+
+
+-- | Class of containers that can escalate contained 'Either's.
+-- The word "Vector" is meant in the sense of a disease transmitter.
+class ChoiceVector v where
+ spreadChoice :: v (Either f a) -> Either f (v a)
+
+-- Let's do a few examples first
+
+instance ChoiceVector Maybe where
+ spreadChoice (Just (Left f)) = Left f
+ spreadChoice (Just (Right x)) = Right (Just x)
+ spreadChoice Nothing = Right Nothing
+
+instance ChoiceVector (Either l) where
+ spreadChoice (Right (Left f)) = Left f
+ spreadChoice (Right (Right x)) = Right (Right x)
+ spreadChoice (Left x ) = Right (Left x)
+
+instance ChoiceVector ((,) a) where
+ spreadChoice (_, Left f) = Left f
+ spreadChoice (x, Right y) = Right (x,y)
+ -- Wasn't there a newtype somewhere with the elements flipped?
+
+--
+-- More instances later, first some discussion.
+--
+-- I'll have to freshen up on type system details to see how (or if) to do
+-- something like
+--
+-- > instance (ChoiceVector a, ChoiceVector b) => ChoiceVector (a b) where
+-- > :
+--
+-- But maybe it would be even better to use something like
+--
+-- > class ChoiceVector v v' f | v -> v' f where
+-- > spreadChoice :: v -> Either f v'
+--
+-- That way, more places in @v@ could spread the cheer, e.g.:
+--
+-- As before:
+-- -- ( a , Either f b) (a , b) f
+-- > instance ChoiceVector ((,) a (Either f b)) ((,) a b) f where
+-- > spreadChoice (_, Left f) = Left f
+-- > spreadChoice (a, Right b) = Right (a,b)
+--
+-- But also:
+-- -- ( Either f a , b) (a , b) f
+-- > instance ChoiceVector ((,) (Either f a) b) ((,) a b) f where
+-- > spreadChoice (Right a,b) = Right (a,b)
+-- > spreadChoice (Left f,_) = Left f
+--
+-- And maybe even:
+-- -- ( Either f a , Either f b) (a , b) f
+-- > instance ChoiceVector ((,) (Either f a) (Either f b)) ((,) a b) f where
+-- > spreadChoice (Right a , Right b) = Right (a,b)
+-- > spreadChoice (Left f , _ ) = Left f
+-- > spreadChoice ( _ , Left f) = Left f
+--
+-- Of course that would lead to a lot of overlapping instances...
+-- But I can't think of a different way. A selector function might help,
+-- but not even a "Data.Traversable" is powerful enough for that.
+-- But maybe someone has already solved all this with a lens library.
+--
+-- Well, it's an interesting academic question. But for practical purposes,
+-- I have more than enough right now.
+
+instance ChoiceVector ((,,) a b) where
+ spreadChoice (_,_, Left f) = Left f
+ spreadChoice (a,b, Right x) = Right (a,b,x)
+
+instance ChoiceVector ((,,,) a b c) where
+ spreadChoice (_,_,_, Left f) = Left f
+ spreadChoice (a,b,c, Right x) = Right (a,b,c,x)
+
+instance ChoiceVector ((,,,,) a b c d) where
+ spreadChoice (_,_,_,_, Left f) = Left f
+ spreadChoice (a,b,c,d, Right x) = Right (a,b,c,d,x)
+
+instance ChoiceVector (Const a) where
+ spreadChoice (Const c) = Right (Const c) -- need to repackage because of implicit types
+
+-- | Fails on the first error
+instance ChoiceVector [] where
+ spreadChoice = sequence -- using the monad instance of Either.
+ -- Could be generalized to "Data.Traversable" - but why play
+ -- with UndecidableInstances unless this is really needed.
+
+-- | Wrapper for a list. While the normal list instance of 'ChoiceVector'
+-- fails whenever it can, this type will never fail.
+newtype SuccessList a = SuccessList { collectNonFailing :: [a] }
+ deriving ( Eq, Ord, Show )
+
+instance ChoiceVector SuccessList where
+ spreadChoice = Right . SuccessList . (foldr unTagRight []) . collectNonFailing
+ where unTagRight (Right x) = (x:)
+ unTagRight _ = id
+
+-- | Like 'catMaybes', but for 'Either'.
+collectRights :: [Either _l r] -> [r]
+collectRights = collectNonFailing . untag . spreadChoice . SuccessList
+ where untag = fromLeft (error "Unexpected Left")
+
+-- | A version of 'collectRights' generalized to other containers. The
+-- container must be both "reducible" and "buildable". Most general containers
+-- should fullfill these requirements, but there is no single typeclass
+-- (that I know of) for that.
+-- Therefore, they are split between 'Foldable' and 'MonadPlus'.
+-- (Note that 'Data.Traversable.Traversable' alone would not be enough, either.)
+collectRightsF :: (F.Foldable c, MonadPlus c) => c (Either _l r) -> c r
+collectRightsF = F.foldr unTagRight mzero
+ where unTagRight (Right x) = mplus $ return x
+ unTagRight _ = id
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs
new file mode 100644
index 000000000..82ae3e20e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs
@@ -0,0 +1,62 @@
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Generic.Namespaces
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+A class containing a set of namespace identifiers. Used to convert between
+typesafe Haskell namespace identifiers and unsafe "real world" namespaces.
+-}
+
+module Text.Pandoc.Readers.Odt.Generic.Namespaces where
+
+import qualified Data.Map as M
+
+--
+type NameSpaceIRI = String
+
+--
+type NameSpaceIRIs nsID = M.Map nsID NameSpaceIRI
+
+--
+class (Eq nsID, Ord nsID) => NameSpaceID nsID where
+
+ -- | Given a IRI, possibly update the map and return the id of the namespace.
+ -- May fail if the namespace is unknown and the application does not
+ -- allow unknown namespaces.
+ getNamespaceID :: NameSpaceIRI
+ -> NameSpaceIRIs nsID
+ -> Maybe (NameSpaceIRIs nsID, nsID)
+ -- | Given a namespace id, lookup its IRI. May be overriden for performance.
+ getIRI :: nsID
+ -> NameSpaceIRIs nsID
+ -> Maybe NameSpaceIRI
+ -- | The root element of an XML document has a namespace, too, and the
+ -- "XML.Light-parser" is eager to remove the corresponding namespace
+ -- attribute.
+ -- As a result, at least this root namespace must be provided.
+ getInitialIRImap :: NameSpaceIRIs nsID
+
+ getIRI = M.lookup
+ getInitialIRImap = M.empty
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs b/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs
new file mode 100644
index 000000000..afd7d616c
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs
@@ -0,0 +1,48 @@
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Generic.SetMap
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+A map of values to sets of values.
+-}
+
+module Text.Pandoc.Readers.Odt.Generic.SetMap where
+
+import qualified Data.Map as M
+import qualified Data.Set as S
+
+type SetMap k v = M.Map k (S.Set v)
+
+empty :: SetMap k v
+empty = M.empty
+
+fromList :: (Ord k, Ord v) => [(k,v)] -> SetMap k v
+fromList = foldr (uncurry insert) empty
+
+insert :: (Ord k, Ord v) => k -> v -> SetMap k v -> SetMap k v
+insert key value setMap = M.insertWith S.union key (S.singleton value) setMap
+
+union3 :: (Ord k) => SetMap k v -> SetMap k v -> SetMap k v -> SetMap k v
+union3 sm1 sm2 sm3 = sm1 `M.union` sm2 `M.union` sm3
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
new file mode 100644
index 000000000..6c10ed61d
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
@@ -0,0 +1,171 @@
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Reader.Odt.Generic.Utils
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+General utility functions for the odt reader.
+-}
+
+module Text.Pandoc.Readers.Odt.Generic.Utils
+( uncurry3
+, uncurry4
+, uncurry5
+, uncurry6
+, uncurry7
+, uncurry8
+, swap
+, reverseComposition
+, bool
+, tryToRead
+, Lookupable(..)
+, readLookupables
+, readLookupable
+, readPercent
+, findBy
+, swing
+, composition
+) where
+
+import Control.Category ( Category, (>>>), (<<<) )
+import qualified Control.Category as Cat ( id )
+import Control.Monad ( msum )
+
+import qualified Data.Foldable as F ( Foldable, foldr )
+import Data.Maybe
+
+
+-- | Aequivalent to
+-- > foldr (.) id
+-- where '(.)' are 'id' are the ones from "Control.Category"
+-- and 'foldr' is the one from "Data.Foldable".
+-- The noun-form was chosen to be consistend with 'sum', 'product' etc
+-- based on the discussion at
+-- <https://groups.google.com/forum/#!topic/haskell-cafe/VkOZM1zaHOI>
+-- (that I was not part of)
+composition :: (Category cat, F.Foldable f) => f (cat a a) -> cat a a
+composition = F.foldr (<<<) Cat.id
+
+-- | Aequivalent to
+-- > foldr (flip (.)) id
+-- where '(.)' are 'id' are the ones from "Control.Category"
+-- and 'foldr' is the one from "Data.Foldable".
+-- A reversed version of 'composition'.
+reverseComposition :: (Category cat, F.Foldable f) => f (cat a a) -> cat a a
+reverseComposition = F.foldr (>>>) Cat.id
+
+-- | 'Either' has 'either', 'Maybe' has 'maybe'. 'Bool' should have 'bool'.
+-- Note that the first value is selected if the boolean value is 'False'.
+-- That makes 'bool' consistent with the other two. Also, 'bool' now takes its
+-- arguments in the exact opposite order compared to the normal if construct.
+bool :: a -> a -> Bool -> a
+bool x _ False = x
+bool _ x True = x
+
+-- | This function often makes it possible to switch values with the functions
+-- that are applied to them.
+--
+-- Examples:
+-- > swing map :: [a -> b] -> a -> [b]
+-- > swing any :: [a -> Bool] -> a -> Bool
+-- > swing foldr :: b -> a -> [a -> b -> b] -> b
+-- > swing scanr :: c -> a -> [a -> c -> c] -> c
+-- > swing zipWith :: [a -> b -> c] -> a -> [b] -> [c]
+-- > swing find :: [a -> Bool] -> a -> Maybe (a -> Bool)
+--
+-- Stolen from <https://wiki.haskell.org/Pointfree>
+swing :: (((a -> b) -> b) -> c -> d) -> c -> a -> d
+swing = flip.(.flip id)
+-- swing f c a = f ($ a) c
+
+
+-- | Alternative to 'read'/'reads'. The former of these throws errors
+-- (nobody wants that) while the latter returns "to much" for simple purposes.
+-- This function instead applies 'reads' and returns the first match (if any)
+-- in a 'Maybe'.
+tryToRead :: (Read r) => String -> Maybe r
+tryToRead = reads >>> listToMaybe >>> fmap fst
+
+-- | A version of 'reads' that requires a '%' sign after the number
+readPercent :: ReadS Int
+readPercent s = [ (i,s') | (i , r ) <- reads s
+ , ("%" , s') <- lex r
+ ]
+
+-- | Data that can be looked up.
+-- This is mostly a utility to read data with kind *.
+class Lookupable a where
+ lookupTable :: [(String, a)]
+
+-- | The idea is to use this function as if there was a declaration like
+--
+-- > instance (Lookupable a) => (Read a) where
+-- > readsPrec _ = readLookupables
+-- .
+-- But including this code in this form would need UndecideableInstances.
+-- That is a bad idea. Luckily 'readLookupable' (without the s at the end)
+-- can be used directly in almost any case.
+readLookupables :: (Lookupable a) => String -> [(a,String)]
+readLookupables s = [ (a,rest) | (word,rest) <- lex s,
+ let result = lookup word lookupTable,
+ isJust result,
+ let Just a = result
+ ]
+
+-- | Very similar to a simple 'lookup' in the 'lookupTable', but with a lexer.
+readLookupable :: (Lookupable a) => String -> Maybe a
+readLookupable s = msum
+ $ map ((`lookup` lookupTable).fst)
+ $ lex s
+
+uncurry3 :: (a->b->c -> z) -> (a,b,c ) -> z
+uncurry4 :: (a->b->c->d -> z) -> (a,b,c,d ) -> z
+uncurry5 :: (a->b->c->d->e -> z) -> (a,b,c,d,e ) -> z
+uncurry6 :: (a->b->c->d->e->f -> z) -> (a,b,c,d,e,f ) -> z
+uncurry7 :: (a->b->c->d->e->f->g -> z) -> (a,b,c,d,e,f,g ) -> z
+uncurry8 :: (a->b->c->d->e->f->g->h -> z) -> (a,b,c,d,e,f,g,h) -> z
+
+uncurry3 fun (a,b,c ) = fun a b c
+uncurry4 fun (a,b,c,d ) = fun a b c d
+uncurry5 fun (a,b,c,d,e ) = fun a b c d e
+uncurry6 fun (a,b,c,d,e,f ) = fun a b c d e f
+uncurry7 fun (a,b,c,d,e,f,g ) = fun a b c d e f g
+uncurry8 fun (a,b,c,d,e,f,g,h) = fun a b c d e f g h
+
+swap :: (a,b) -> (b,a)
+swap (a,b) = (b,a)
+
+-- | A version of "Data.List.find" that uses a converter to a Maybe instance.
+-- The returned value is the first which the converter returns in a 'Just'
+-- wrapper.
+findBy :: (a -> Maybe b) -> [a] -> Maybe b
+findBy _ [] = Nothing
+findBy f ((f -> Just x):_ ) = Just x
+findBy f ( _:xs) = findBy f xs
+
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
new file mode 100644
index 000000000..ec7e0ea5e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
@@ -0,0 +1,1064 @@
+{-# LANGUAGE Arrows #-}
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE RecordWildCards #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.Generic.XMLConverter
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+A generalized XML parser based on stateful arrows.
+It might be sufficient to define this reader as a comonad, but there is
+not a lot of use in trying.
+-}
+
+module Text.Pandoc.Readers.Odt.Generic.XMLConverter
+( ElementName
+, XMLConverterState
+, XMLConverter
+, FallibleXMLConverter
+, swapPosition
+, runConverter
+, runConverter''
+, runConverter'
+, runConverterF'
+, runConverterF
+, getCurrentElement
+, getExtraState
+, setExtraState
+, modifyExtraState
+, convertingExtraState
+, producingExtraState
+, lookupNSiri
+, lookupNSprefix
+, readNSattributes
+, elemName
+, elemNameIs
+, strContent
+, elContent
+, currentElem
+, currentElemIs
+, expectElement
+, elChildren
+, findChildren
+, filterChildren
+, filterChildrenName
+, findChild'
+, findChild
+, filterChild'
+, filterChild
+, filterChildName'
+, filterChildName
+, isSet
+, isSet'
+, isSetWithDefault
+, hasAttrValueOf'
+, failIfNotAttrValueOf
+, isThatTheAttrValue
+, searchAttrIn
+, searchAttrWith
+, searchAttr
+, lookupAttr
+, lookupAttr'
+, lookupAttrWithDefault
+, lookupDefaultingAttr
+, findAttr'
+, findAttr
+, findAttrWithDefault
+, readAttr
+, readAttr'
+, readAttrWithDefault
+, getAttr
+-- , (>/<)
+-- , (?>/<)
+, executeIn
+, collectEvery
+, withEveryL
+, withEvery
+, tryAll
+, tryAll'
+, IdXMLConverter
+, MaybeEConverter
+, ElementMatchConverter
+, MaybeCConverter
+, ContentMatchConverter
+, makeMatcherE
+, makeMatcherC
+, prepareMatchersE
+, prepareMatchersC
+, matchChildren
+, matchContent''
+, matchContent'
+, matchContent
+) where
+
+import Control.Applicative hiding ( liftA, liftA2 )
+import Control.Monad ( MonadPlus )
+import Control.Arrow
+
+import qualified Data.Map as M
+import qualified Data.Foldable as F
+import Data.Default
+import Data.Monoid ( Monoid )
+import Data.Maybe
+
+import qualified Text.XML.Light as XML
+
+import Text.Pandoc.Readers.Odt.Arrows.State
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+
+import Text.Pandoc.Readers.Odt.Generic.Namespaces
+import Text.Pandoc.Readers.Odt.Generic.Utils
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+
+--------------------------------------------------------------------------------
+-- Basis types for readability
+--------------------------------------------------------------------------------
+
+--
+type ElementName = String
+type AttributeName = String
+type AttributeValue = String
+
+--
+type NameSpacePrefix = String
+
+--
+type NameSpacePrefixes nsID = M.Map nsID NameSpacePrefix
+
+--------------------------------------------------------------------------------
+-- Main converter state
+--------------------------------------------------------------------------------
+
+-- GADT so some of the NameSpaceID restrictions can be deduced
+data XMLConverterState nsID extraState where
+ XMLConverterState :: NameSpaceID nsID
+ => { -- | A stack of parent elements. The top element is the current one.
+ -- Arguably, a real Zipper would be better. But that is an
+ -- optimization that can be made at a later time, e.g. when
+ -- replacing Text.XML.Light.
+ parentElements :: [XML.Element]
+ -- | A map from internal namespace IDs to the namespace prefixes
+ -- used in XML elements
+ , namespacePrefixes :: NameSpacePrefixes nsID
+ -- | A map from internal namespace IDs to namespace IRIs
+ -- (Only necessary for matching namespace IDs and prefixes)
+ , namespaceIRIs :: NameSpaceIRIs nsID
+ -- | A place to put "something else". This feature is used heavily
+ -- to keep the main code cleaner. More specifically, the main reader
+ -- is divided into different stages. Each stage lifts something up
+ -- here, which the next stage can then use. This could of course be
+ -- generalized to a state-tree or used for the namespace IRIs. The
+ -- border between states and values is an imaginary one, after all.
+ -- But the separation as it is seems to be enough for now.
+ , moreState :: extraState
+ }
+ -> XMLConverterState nsID extraState
+
+--
+createStartState :: (NameSpaceID nsID)
+ => XML.Element
+ -> extraState
+ -> XMLConverterState nsID extraState
+createStartState element extraState =
+ XMLConverterState
+ { parentElements = [element]
+ , namespacePrefixes = M.empty
+ , namespaceIRIs = getInitialIRImap
+ , moreState = extraState
+ }
+
+-- | Functor over extra state
+instance Functor (XMLConverterState nsID) where
+ fmap f ( XMLConverterState parents prefixes iRIs extraState )
+ = XMLConverterState parents prefixes iRIs (f extraState)
+
+--
+replaceExtraState :: extraState
+ -> XMLConverterState nsID _x
+ -> XMLConverterState nsID extraState
+replaceExtraState x s
+ = fmap (const x) s
+
+--
+currentElement :: XMLConverterState nsID extraState
+ -> XML.Element
+currentElement state = head (parentElements state)
+
+-- | Replace the current position by another, modifying the extra state
+-- in the process
+swapPosition :: (extraState -> extraState')
+ -> [XML.Element]
+ -> XMLConverterState nsID extraState
+ -> XMLConverterState nsID extraState'
+swapPosition f stack state
+ = state { parentElements = stack
+ , moreState = f (moreState state)
+ }
+
+-- | Replace the current position by another, modifying the extra state
+-- in the process
+swapStack' :: XMLConverterState nsID extraState
+ -> [XML.Element]
+ -> ( XMLConverterState nsID extraState , [XML.Element] )
+swapStack' state stack
+ = ( state { parentElements = stack }
+ , parentElements state
+ )
+
+--
+pushElement :: XML.Element
+ -> XMLConverterState nsID extraState
+ -> XMLConverterState nsID extraState
+pushElement e state = state { parentElements = e:(parentElements state) }
+
+-- | Pop the top element from the call stack, unless it is the last one.
+popElement :: XMLConverterState nsID extraState
+ -> Maybe (XMLConverterState nsID extraState)
+popElement state
+ | _:es@(_:_) <- parentElements state = Just $ state { parentElements = es }
+ | otherwise = Nothing
+
+--------------------------------------------------------------------------------
+-- Main type
+--------------------------------------------------------------------------------
+
+-- It might be a good idea to pack the converters in a GADT
+-- Downside: data instead of type
+-- Upside: 'Failure' could be made a parameter as well.
+
+--
+type XMLConverter nsID extraState input output
+ = ArrowState (XMLConverterState nsID extraState ) input output
+
+type FallibleXMLConverter nsID extraState input output
+ = XMLConverter nsID extraState input (Fallible output)
+
+--
+runConverter :: XMLConverter nsID extraState input output
+ -> XMLConverterState nsID extraState
+ -> input
+ -> output
+runConverter converter state input = snd $ runArrowState converter (state,input)
+
+--
+runConverter'' :: (NameSpaceID nsID)
+ => XMLConverter nsID extraState (Fallible ()) output
+ -> extraState
+ -> XML.Element
+ -> output
+runConverter'' converter extraState element = runConverter (readNSattributes >>> converter) (createStartState element extraState) ()
+
+runConverter' :: (NameSpaceID nsID)
+ => FallibleXMLConverter nsID extraState () success
+ -> extraState
+ -> XML.Element
+ -> Fallible success
+runConverter' converter extraState element = runConverter (readNSattributes >>? converter) (createStartState element extraState) ()
+
+--
+runConverterF' :: FallibleXMLConverter nsID extraState x y
+ -> XMLConverterState nsID extraState
+ -> Fallible x -> Fallible y
+runConverterF' a s e = runConverter (returnV e >>? a) s e
+
+--
+runConverterF :: (NameSpaceID nsID)
+ => FallibleXMLConverter nsID extraState XML.Element x
+ -> extraState
+ -> Fallible XML.Element -> Fallible x
+runConverterF a s = either failWith
+ (\e -> runConverter a (createStartState e s) e)
+
+--
+getCurrentElement :: XMLConverter nsID extraState x XML.Element
+getCurrentElement = extractFromState currentElement
+
+--
+getExtraState :: XMLConverter nsID extraState x extraState
+getExtraState = extractFromState moreState
+
+--
+setExtraState :: XMLConverter nsID extraState extraState extraState
+setExtraState = withState $ \state extra
+ -> (replaceExtraState extra state , extra)
+
+
+-- | Lifts a function to the extra state.
+modifyExtraState :: (extraState -> extraState)
+ -> XMLConverter nsID extraState x x
+modifyExtraState = modifyState.fmap
+
+
+-- | First sets the extra state to the new value. Then modifies the original
+-- extra state with a converter that uses the new state. Finally, the
+-- intermediate state is dropped and the extra state is lifted into the
+-- state as it was at the beginning of the function.
+-- As a result, exactly the extra state and nothing else is changed.
+-- The resulting converter even behaves like an identity converter on the
+-- value level.
+--
+-- (The -ing form is meant to be mnemonic in a sequence of arrows as in
+-- convertingExtraState () converter >>> doOtherStuff)
+--
+convertingExtraState :: extraState'
+ -> FallibleXMLConverter nsID extraState' extraState extraState
+ -> FallibleXMLConverter nsID extraState x x
+convertingExtraState v a = withSubStateF setVAsExtraState modifyWithA
+ where
+ setVAsExtraState = liftAsSuccess $ extractFromState id >>^ replaceExtraState v
+ modifyWithA = keepingTheValue (moreState ^>> a)
+ >>^ spreadChoice >>?§ flip replaceExtraState
+
+-- | First sets the extra state to the new value. Then produces a new
+-- extra state with a converter that uses the new state. Finally, the
+-- intermediate state is dropped and the extra state is lifted into the
+-- state as it was at the beginning of the function.
+-- As a result, exactly the extra state and nothing else is changed.
+-- The resulting converter even behaves like an identity converter on the
+-- value level.
+--
+-- Aequivalent to
+--
+-- > \v x a -> convertingExtraState v (returnV x >>> a)
+--
+-- (The -ing form is meant to be mnemonic in a sequence of arrows as in
+-- producingExtraState () () producer >>> doOtherStuff)
+--
+producingExtraState :: extraState'
+ -> a
+ -> FallibleXMLConverter nsID extraState' a extraState
+ -> FallibleXMLConverter nsID extraState x x
+producingExtraState v x a = convertingExtraState v (returnV x >>> a)
+
+
+--------------------------------------------------------------------------------
+-- Work in namespaces
+--------------------------------------------------------------------------------
+
+-- | Arrow version of 'getIRI'
+lookupNSiri :: (NameSpaceID nsID)
+ => nsID
+ -> XMLConverter nsID extraState x (Maybe NameSpaceIRI)
+lookupNSiri nsID = extractFromState
+ $ \state -> getIRI nsID $ namespaceIRIs state
+
+--
+lookupNSprefix :: (NameSpaceID nsID)
+ => nsID
+ -> XMLConverter nsID extraState x (Maybe NameSpacePrefix)
+lookupNSprefix nsID = extractFromState
+ $ \state -> M.lookup nsID $ namespacePrefixes state
+
+-- | Extracts namespace attributes from the current element and tries to
+-- update the current mapping accordingly
+readNSattributes :: (NameSpaceID nsID)
+ => FallibleXMLConverter nsID extraState x ()
+readNSattributes = fromState $ \state -> maybe (state, failEmpty )
+ ( , succeedWith ())
+ (extractNSAttrs state )
+ where
+ extractNSAttrs :: (NameSpaceID nsID)
+ => XMLConverterState nsID extraState
+ -> Maybe (XMLConverterState nsID extraState)
+ extractNSAttrs startState
+ = foldl (\state d -> state >>= addNS d)
+ (Just startState)
+ nsAttribs
+ where nsAttribs = mapMaybe readNSattr (XML.elAttribs element)
+ element = currentElement startState
+ readNSattr (XML.Attr (XML.QName name _ (Just "xmlns")) iri)
+ = Just (name, iri)
+ readNSattr _ = Nothing
+ addNS (prefix, iri) state = fmap updateState
+ $ getNamespaceID iri
+ $ namespaceIRIs state
+ where updateState (iris,nsID)
+ = state { namespaceIRIs = iris
+ , namespacePrefixes = M.insert nsID prefix
+ $ namespacePrefixes state
+ }
+
+--------------------------------------------------------------------------------
+-- Common namespace accessors
+--------------------------------------------------------------------------------
+
+-- | Given a namespace id and an element name, creates a 'XML.QName' for
+-- internal use
+elemName :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> XMLConverter nsID extraState x XML.QName
+elemName nsID name = lookupNSiri nsID
+ &&& lookupNSprefix nsID
+ >>§ XML.QName name
+
+-- | Checks if a given element matches both a specified namespace id
+-- and a specified element name
+elemNameIs :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> XMLConverter nsID extraState XML.Element Bool
+elemNameIs nsID name = keepingTheValue (lookupNSiri nsID) >>§ hasThatName
+ where hasThatName e iri = let elName = XML.elName e
+ in XML.qName elName == name
+ && XML.qURI elName == iri
+
+--------------------------------------------------------------------------------
+-- General content
+--------------------------------------------------------------------------------
+
+--
+strContent :: XMLConverter nsID extraState x String
+strContent = getCurrentElement
+ >>^ XML.strContent
+
+--
+elContent :: XMLConverter nsID extraState x [XML.Content]
+elContent = getCurrentElement
+ >>^ XML.elContent
+
+--------------------------------------------------------------------------------
+-- Current element
+--------------------------------------------------------------------------------
+
+--
+currentElem :: XMLConverter nsID extraState x (XML.QName)
+currentElem = getCurrentElement
+ >>^ XML.elName
+
+currentElemIs :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> XMLConverter nsID extraState x Bool
+currentElemIs nsID name = getCurrentElement
+ >>> elemNameIs nsID name
+
+
+
+{-
+currentElemIs'' nsID name = ( (getCurrentElement >>^ XML.elName >>>
+ (XML.qName >>^ (&&).(== name) )
+ ^&&&^
+ (XML.qIRI >>^ (==) )
+ ) >>§ (.)
+ ) &&& lookupNSiri nsID >>§ ($)
+-}
+
+--
+expectElement :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState x ()
+expectElement nsID name = currentElemIs nsID name
+ >>^ boolToChoice
+
+--------------------------------------------------------------------------------
+-- Chilren
+--------------------------------------------------------------------------------
+
+--
+elChildren :: XMLConverter nsID extraState x [XML.Element]
+elChildren = getCurrentElement
+ >>^ XML.elChildren
+
+--
+findChildren :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> XMLConverter nsID extraState x [XML.Element]
+findChildren nsID name = elemName nsID name
+ &&& getCurrentElement
+ >>§ XML.findChildren
+
+--
+filterChildren :: (XML.Element -> Bool)
+ -> XMLConverter nsID extraState x [XML.Element]
+filterChildren p = getCurrentElement
+ >>^ XML.filterChildren p
+
+--
+filterChildrenName :: (XML.QName -> Bool)
+ -> XMLConverter nsID extraState x [XML.Element]
+filterChildrenName p = getCurrentElement
+ >>^ XML.filterChildrenName p
+
+--
+findChild' :: (NameSpaceID nsID)
+ => nsID
+ -> ElementName
+ -> XMLConverter nsID extraState x (Maybe XML.Element)
+findChild' nsID name = elemName nsID name
+ &&& getCurrentElement
+ >>§ XML.findChild
+
+--
+findChild :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState x XML.Element
+findChild nsID name = findChild' nsID name
+ >>> maybeToChoice
+
+--
+filterChild' :: (XML.Element -> Bool)
+ -> XMLConverter nsID extraState x (Maybe XML.Element)
+filterChild' p = getCurrentElement
+ >>^ XML.filterChild p
+
+--
+filterChild :: (XML.Element -> Bool)
+ -> FallibleXMLConverter nsID extraState x XML.Element
+filterChild p = filterChild' p
+ >>> maybeToChoice
+
+--
+filterChildName' :: (XML.QName -> Bool)
+ -> XMLConverter nsID extraState x (Maybe XML.Element)
+filterChildName' p = getCurrentElement
+ >>^ XML.filterChildName p
+
+--
+filterChildName :: (XML.QName -> Bool)
+ -> FallibleXMLConverter nsID extraState x XML.Element
+filterChildName p = filterChildName' p
+ >>> maybeToChoice
+
+
+--------------------------------------------------------------------------------
+-- Attributes
+--------------------------------------------------------------------------------
+
+--
+isSet :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> (Either Failure Bool)
+ -> FallibleXMLConverter nsID extraState x Bool
+isSet nsID attrName deflt
+ = findAttr' nsID attrName
+ >>^ maybe deflt stringToBool
+
+--
+isSet' :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x (Maybe Bool)
+isSet' nsID attrName = findAttr' nsID attrName
+ >>^ (>>= stringToBool')
+
+isSetWithDefault :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> Bool
+ -> XMLConverter nsID extraState x Bool
+isSetWithDefault nsID attrName def'
+ = isSet' nsID attrName
+ >>^ fromMaybe def'
+
+--
+hasAttrValueOf' :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> AttributeValue
+ -> XMLConverter nsID extraState x Bool
+hasAttrValueOf' nsID attrName attrValue
+ = findAttr nsID attrName
+ >>> ( const False ^|||^ (==attrValue))
+
+--
+failIfNotAttrValueOf :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> AttributeValue
+ -> FallibleXMLConverter nsID extraState x ()
+failIfNotAttrValueOf nsID attrName attrValue
+ = hasAttrValueOf' nsID attrName attrValue
+ >>^ boolToChoice
+
+-- | Is the value that is currently transported in the arrow the value of
+-- the specified attribute?
+isThatTheAttrValue :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> FallibleXMLConverter nsID extraState AttributeValue Bool
+isThatTheAttrValue nsID attrName
+ = keepingTheValue
+ (findAttr nsID attrName)
+ >>§ right.(==)
+
+-- | Lookup value in a dictionary, fail if no attribute found or value
+-- not in dictionary
+searchAttrIn :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> [(AttributeValue,a)]
+ -> FallibleXMLConverter nsID extraState x a
+searchAttrIn nsID attrName dict
+ = findAttr nsID attrName
+ >>?^? maybeToChoice.(`lookup` dict )
+
+
+-- | Lookup value in a dictionary. Fail if no attribute found. If value not in
+-- dictionary, return default value
+searchAttrWith :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> a
+ -> [(AttributeValue,a)]
+ -> FallibleXMLConverter nsID extraState x a
+searchAttrWith nsID attrName defV dict
+ = findAttr nsID attrName
+ >>?^ (fromMaybe defV).(`lookup` dict )
+
+-- | Lookup value in a dictionary. If attribute or value not found,
+-- return default value
+searchAttr :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> a
+ -> [(AttributeValue,a)]
+ -> XMLConverter nsID extraState x a
+searchAttr nsID attrName defV dict
+ = searchAttrIn nsID attrName dict
+ >>> const defV ^|||^ id
+
+-- | Read a 'Lookupable' attribute. Fail if no match.
+lookupAttr :: (NameSpaceID nsID, Lookupable a)
+ => nsID -> AttributeName
+ -> FallibleXMLConverter nsID extraState x a
+lookupAttr nsID attrName = lookupAttr' nsID attrName
+ >>^ maybeToChoice
+
+
+-- | Read a 'Lookupable' attribute. Return the result as a 'Maybe'.
+lookupAttr' :: (NameSpaceID nsID, Lookupable a)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x (Maybe a)
+lookupAttr' nsID attrName
+ = findAttr' nsID attrName
+ >>^ (>>= readLookupable)
+
+-- | Read a 'Lookupable' attribute with explicit default
+lookupAttrWithDefault :: (NameSpaceID nsID, Lookupable a)
+ => nsID -> AttributeName
+ -> a
+ -> XMLConverter nsID extraState x a
+lookupAttrWithDefault nsID attrName deflt
+ = lookupAttr' nsID attrName
+ >>^ fromMaybe deflt
+
+-- | Read a 'Lookupable' attribute with implicit default
+lookupDefaultingAttr :: (NameSpaceID nsID, Lookupable a, Default a)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x a
+lookupDefaultingAttr nsID attrName
+ = lookupAttrWithDefault nsID attrName def
+
+-- | Return value as a (Maybe String)
+findAttr' :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x (Maybe AttributeValue)
+findAttr' nsID attrName = elemName nsID attrName
+ &&& getCurrentElement
+ >>§ XML.findAttr
+
+-- | Return value as string or fail
+findAttr :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> FallibleXMLConverter nsID extraState x AttributeValue
+findAttr nsID attrName = findAttr' nsID attrName
+ >>> maybeToChoice
+
+-- | Return value as string or return provided default value
+findAttrWithDefault :: (NameSpaceID nsID)
+ => nsID -> AttributeName
+ -> AttributeValue
+ -> XMLConverter nsID extraState x AttributeValue
+findAttrWithDefault nsID attrName deflt
+ = findAttr' nsID attrName
+ >>^ fromMaybe deflt
+
+-- | Read and return value or fail
+readAttr :: (NameSpaceID nsID, Read attrValue)
+ => nsID -> AttributeName
+ -> FallibleXMLConverter nsID extraState x attrValue
+readAttr nsID attrName = readAttr' nsID attrName
+ >>> maybeToChoice
+
+-- | Read and return value or return Nothing
+readAttr' :: (NameSpaceID nsID, Read attrValue)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x (Maybe attrValue)
+readAttr' nsID attrName = findAttr' nsID attrName
+ >>^ (>>= tryToRead)
+
+-- | Read and return value or return provided default value
+readAttrWithDefault :: (NameSpaceID nsID, Read attrValue)
+ => nsID -> AttributeName
+ -> attrValue
+ -> XMLConverter nsID extraState x attrValue
+readAttrWithDefault nsID attrName deflt
+ = findAttr' nsID attrName
+ >>^ (>>= tryToRead)
+ >>^ fromMaybe deflt
+
+-- | Read and return value or return default value from 'Default' instance
+getAttr :: (NameSpaceID nsID, Read attrValue, Default attrValue)
+ => nsID -> AttributeName
+ -> XMLConverter nsID extraState x attrValue
+getAttr nsID attrName = readAttrWithDefault nsID attrName def
+
+--------------------------------------------------------------------------------
+-- Movements
+--------------------------------------------------------------------------------
+
+--
+jumpThere :: XMLConverter nsID extraState XML.Element XML.Element
+jumpThere = withState (\state element
+ -> ( pushElement element state , element )
+ )
+
+--
+swapStack :: XMLConverter nsID extraState [XML.Element] [XML.Element]
+swapStack = withState swapStack'
+
+--
+jumpBack :: FallibleXMLConverter nsID extraState _x _x
+jumpBack = tryModifyState (popElement >>> maybeToChoice)
+
+-- | Support function for "procedural" converters: jump to an element, execute
+-- a converter, jump back.
+-- This version is safer than 'executeThere', because it does not rely on the
+-- internal stack. As a result, the converter can not move around in arbitrary
+-- ways. The downside is of course that some of the environment is not
+-- accessible to the converter.
+switchingTheStack :: XMLConverter nsID moreState a b
+ -> XMLConverter nsID moreState (a, XML.Element) b
+switchingTheStack a = second ( (:[]) ^>> swapStack )
+ >>> first a
+ >>> second swapStack
+ >>^ fst
+
+-- | Support function for "procedural" converters: jumps to an element, executes
+-- a converter, jumps back.
+-- Make sure that the converter is well-behaved; that is it should
+-- return to the exact position it started from in /every possible path/ of
+-- execution, even if it "fails". If it does not, you may encounter
+-- strange bugs. If you are not sure about the behaviour or want to use
+-- shortcuts, you can often use 'switchingTheStack' instead.
+executeThere :: FallibleXMLConverter nsID moreState a b
+ -> FallibleXMLConverter nsID moreState (a, XML.Element) b
+executeThere a = second jumpThere
+ >>> fst
+ ^>> a
+ >>> jumpBack -- >>? jumpBack would not ensure the jump.
+ >>^ collapseEither
+
+-- | Do something in a sub-element, tnen come back
+executeIn :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState f s
+ -> FallibleXMLConverter nsID extraState f s
+executeIn nsID name a = keepingTheValue
+ (findChild nsID name)
+ >>> ignoringState liftFailure
+ >>? switchingTheStack a
+ where liftFailure (_, (Left f)) = Left f
+ liftFailure (x, (Right e)) = Right (x, e)
+
+--------------------------------------------------------------------------------
+-- Iterating over children
+--------------------------------------------------------------------------------
+
+-- Helper converter to prepare different types of iterations.
+-- It lifts the children (of a certain type) of the current element
+-- into the value level and pairs each one with the current input value.
+prepareIteration :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> XMLConverter nsID extraState b [(b, XML.Element)]
+prepareIteration nsID name = keepingTheValue
+ (findChildren nsID name)
+ >>§ distributeValue
+
+-- | Applies a converter to every child element of a specific type.
+-- Collects results in a 'Monoid'.
+-- Fails completely if any conversion fails.
+collectEvery :: (NameSpaceID nsID, Monoid m)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState a m
+ -> FallibleXMLConverter nsID extraState a m
+collectEvery nsID name a = prepareIteration nsID name
+ >>> foldS' (switchingTheStack a)
+
+--
+withEveryL :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState a b
+ -> FallibleXMLConverter nsID extraState a [b]
+withEveryL = withEvery
+
+-- | Applies a converter to every child element of a specific type.
+-- Collects results in a 'MonadPlus'.
+-- Fails completely if any conversion fails.
+withEvery :: (NameSpaceID nsID, MonadPlus m)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState a b
+ -> FallibleXMLConverter nsID extraState a (m b)
+withEvery nsID name a = prepareIteration nsID name
+ >>> iterateS' (switchingTheStack a)
+
+-- | Applies a converter to every child element of a specific type.
+-- Collects all successful results in a list.
+tryAll :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState b a
+ -> XMLConverter nsID extraState b [a]
+tryAll nsID name a = prepareIteration nsID name
+ >>> iterateS (switchingTheStack a)
+ >>^ collectRights
+
+-- | Applies a converter to every child element of a specific type.
+-- Collects all successful results.
+tryAll' :: (NameSpaceID nsID, F.Foldable c, MonadPlus c)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState b a
+ -> XMLConverter nsID extraState b (c a)
+tryAll' nsID name a = prepareIteration nsID name
+ >>> iterateS (switchingTheStack a)
+ >>^ collectRightsF
+
+--------------------------------------------------------------------------------
+-- Matching children
+--------------------------------------------------------------------------------
+
+type IdXMLConverter nsID moreState x
+ = XMLConverter nsID moreState x x
+
+type MaybeEConverter nsID moreState x
+ = Maybe (IdXMLConverter nsID moreState (x, XML.Element))
+
+-- Chainable converter that helps deciding which converter to actually use.
+type ElementMatchConverter nsID extraState x
+ = IdXMLConverter nsID
+ extraState
+ (MaybeEConverter nsID extraState x, XML.Element)
+
+type MaybeCConverter nsID moreState x
+ = Maybe (IdXMLConverter nsID moreState (x, XML.Content))
+
+-- Chainable converter that helps deciding which converter to actually use.
+type ContentMatchConverter nsID extraState x
+ = IdXMLConverter nsID
+ extraState
+ (MaybeCConverter nsID extraState x, XML.Content)
+
+-- Helper function: The @c@ is actually a converter that is to be selected by
+-- matching XML elements to the first two parameters.
+-- The fold used to match elements however is very simple, so to use it,
+-- this function wraps the converter in another converter that unifies
+-- the accumulator. Think of a lot of converters with the resulting type
+-- chained together. The accumulator not only transports the element
+-- unchanged to the next matcher, it also does the actual selecting by
+-- combining the intermediate results with '(<|>)'.
+makeMatcherE :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState a a
+ -> ElementMatchConverter nsID extraState a
+makeMatcherE nsID name c = ( second (
+ elemNameIs nsID name
+ >>^ bool Nothing (Just tryC)
+ )
+ >>§ (<|>)
+ ) &&&^ snd
+ where tryC = (fst ^&&& executeThere c >>§ recover) &&&^ snd
+
+-- Helper function: The @c@ is actually a converter that is to be selected by
+-- matching XML content to the first two parameters.
+-- The fold used to match elements however is very simple, so to use it,
+-- this function wraps the converter in another converter that unifies
+-- the accumulator. Think of a lot of converters with the resulting type
+-- chained together. The accumulator not only transports the element
+-- unchanged to the next matcher, it also does the actual selecting by
+-- combining the intermediate results with '(<|>)'.
+makeMatcherC :: (NameSpaceID nsID)
+ => nsID -> ElementName
+ -> FallibleXMLConverter nsID extraState a a
+ -> ContentMatchConverter nsID extraState a
+makeMatcherC nsID name c = ( second ( contentToElem
+ >>> returnV Nothing
+ ||| ( elemNameIs nsID name
+ >>^ bool Nothing (Just cWithJump)
+ )
+ )
+ >>§ (<|>)
+ ) &&&^ snd
+ where cWithJump = ( fst
+ ^&&& ( second contentToElem
+ >>> spreadChoice
+ ^>>? executeThere c
+ )
+ >>§ recover)
+ &&&^ snd
+ contentToElem :: FallibleXMLConverter nsID extraState XML.Content XML.Element
+ contentToElem = arr $ \e -> case e of
+ XML.Elem e' -> succeedWith e'
+ _ -> failEmpty
+
+-- Creates and chains a bunch of matchers
+prepareMatchersE :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState x x)]
+ -> ElementMatchConverter nsID extraState x
+--prepareMatchersE = foldSs . (map $ uncurry3 makeMatcherE)
+prepareMatchersE = reverseComposition . (map $ uncurry3 makeMatcherE)
+
+-- Creates and chains a bunch of matchers
+prepareMatchersC :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState x x)]
+ -> ContentMatchConverter nsID extraState x
+--prepareMatchersC = foldSs . (map $ uncurry3 makeMatcherC)
+prepareMatchersC = reverseComposition . (map $ uncurry3 makeMatcherC)
+
+-- | Takes a list of element-data - converter groups and
+-- * Finds all children of the current element
+-- * Matches each group to each child in order (at most one group per child)
+-- * Filters non-matched children
+-- * Chains all found converters in child-order
+-- * Applies the chain to the input element
+matchChildren :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
+ -> XMLConverter nsID extraState a a
+matchChildren lookups = let matcher = prepareMatchersE lookups
+ in keepingTheValue (
+ elChildren
+ >>> map (Nothing,)
+ ^>> iterateSL matcher
+ >>^ catMaybes.map (\(m,e) -> fmap (swallowElem e) m)
+ -- >>> foldSs
+ >>> reverseComposition
+ )
+ >>> swap
+ ^>> app
+ where
+ -- let the converter swallow the element and drop the element
+ -- in the return value
+ swallowElem element converter = (,element) ^>> converter >>^ fst
+
+--
+matchContent'' :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
+ -> XMLConverter nsID extraState a a
+matchContent'' lookups = let matcher = prepareMatchersC lookups
+ in keepingTheValue (
+ elContent
+ >>> map (Nothing,)
+ ^>> iterateSL matcher
+ >>^ catMaybes.map (\(m,c) -> fmap (swallowContent c) m)
+ -- >>> foldSs
+ >>> reverseComposition
+ )
+ >>> swap
+ ^>> app
+ where
+ -- let the converter swallow the content and drop the content
+ -- in the return value
+ swallowContent content converter = (,content) ^>> converter >>^ fst
+
+
+-- | Takes a list of element-data - converter groups and
+-- * Finds all content of the current element
+-- * Matches each group to each piece of content in order
+-- (at most one group per piece of content)
+-- * Filters non-matched content
+-- * Chains all found converters in content-order
+-- * Applies the chain to the input element
+matchContent' :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
+ -> XMLConverter nsID extraState a a
+matchContent' lookups = matchContent lookups (arr fst)
+
+-- | Takes a list of element-data - converter groups and
+-- * Finds all content of the current element
+-- * Matches each group to each piece of content in order
+-- (at most one group per piece of content)
+-- * Adds a default converter for all non-matched content
+-- * Chains all found converters in content-order
+-- * Applies the chain to the input element
+matchContent :: (NameSpaceID nsID)
+ => [(nsID, ElementName, FallibleXMLConverter nsID extraState a a)]
+ -> XMLConverter nsID extraState (a,XML.Content) a
+ -> XMLConverter nsID extraState a a
+matchContent lookups fallback
+ = let matcher = prepareMatchersC lookups
+ in keepingTheValue (
+ elContent
+ >>> map (Nothing,)
+ ^>> iterateSL matcher
+ >>^ map swallowOrFallback
+ -- >>> foldSs
+ >>> reverseComposition
+ )
+ >>> swap
+ ^>> app
+ where
+ -- let the converter swallow the content and drop the content
+ -- in the return value
+ swallowOrFallback (Just converter,content) = (,content) ^>> converter >>^ fst
+ swallowOrFallback (Nothing ,content) = (,content) ^>> fallback
+
+--------------------------------------------------------------------------------
+-- Internals
+--------------------------------------------------------------------------------
+
+stringToBool :: (Monoid failure) => String -> Either failure Bool
+stringToBool val -- stringToBool' val >>> maybeToChoice
+ | val `elem` trueValues = succeedWith True
+ | val `elem` falseValues = succeedWith False
+ | otherwise = failEmpty
+ where trueValues = ["true" ,"on" ,"1"]
+ falseValues = ["false","off","0"]
+
+stringToBool' :: String -> Maybe Bool
+stringToBool' val | val `elem` trueValues = Just True
+ | val `elem` falseValues = Just False
+ | otherwise = Nothing
+ where trueValues = ["true" ,"on" ,"1"]
+ falseValues = ["false","off","0"]
+
+
+distributeValue :: a -> [b] -> [(a,b)]
+distributeValue = map.(,)
+
+--------------------------------------------------------------------------------
+
+{-
+NOTES
+It might be a good idea to refactor the namespace stuff.
+E.g.: if a namespace constructor took a string as a parameter, things like
+> a ?>/< (NsText,"body")
+would be nicer.
+Together with a rename and some trickery, something like
+> |< NsText "body" >< NsText "p" ?> a </> </>|
+might even be possible.
+
+Some day, XML.Light should be replaced by something better.
+While doing that, it might be useful to replace String as the type of element
+names with something else, too. (Of course with OverloadedStrings).
+While doing that, maybe the types can be created in a way that something like
+> NsText:"body"
+could be used. Overloading (:) does not sounds like the best idea, but if the
+element name type was a list, this might be possible.
+Of course that would be a bit hackish, so the "right" way would probably be
+something like
+> InNS NsText "body"
+but isn't that a bit boring? ;)
+-}
diff --git a/src/Text/Pandoc/Readers/Odt/Namespaces.hs b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
new file mode 100644
index 000000000..e28056814
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/Namespaces.hs
@@ -0,0 +1,110 @@
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Reader.Odt.Namespaces
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Namespaces used in odt files.
+-}
+
+module Text.Pandoc.Readers.Odt.Namespaces ( Namespace (..)
+ ) where
+
+import Data.List ( isPrefixOf )
+import Data.Maybe ( fromMaybe, listToMaybe )
+import qualified Data.Map as M ( empty, insert )
+
+import Text.Pandoc.Readers.Odt.Generic.Namespaces
+
+
+instance NameSpaceID Namespace where
+
+ getInitialIRImap = nsIDmap
+
+ getNamespaceID "" m = Just(m, NsXML)
+ getNamespaceID iri m = asPair $ fromMaybe (NsOther iri) (findID iri)
+ where asPair nsID = Just (M.insert nsID iri m, nsID)
+
+
+findID :: NameSpaceIRI -> Maybe Namespace
+findID iri = listToMaybe [nsID | (iri',~nsID) <- nsIDs, iri' `isPrefixOf` iri]
+
+nsIDmap :: NameSpaceIRIs Namespace
+nsIDmap = foldr (uncurry $ flip M.insert) M.empty nsIDs
+
+data Namespace = -- Open Document core
+ NsOffice | NsStyle | NsText | NsTable | NsForm
+ | NsDraw | Ns3D | NsAnim | NsChart | NsConfig
+ | NsDB | NsMeta | NsNumber | NsScript | NsManifest
+ | NsPresentation
+ -- Metadata
+ | NsODF
+ -- Compatible elements
+ | NsXSL_FO | NsSVG | NsSmil
+ -- External standards
+ | NsMathML | NsXForms | NsXLink | NsXHtml | NsGRDDL
+ | NsDublinCore
+ -- Metadata manifest
+ | NsPKG
+ -- Others
+ | NsOpenFormula
+ -- Core XML (basically only for the 'id'-attribute)
+ | NsXML
+ -- Fallback
+ | NsOther String
+ deriving ( Eq, Ord, Show )
+
+-- | Not the actual iri's, but large prefixes of them - this way there are
+-- less versioning problems and the like.
+nsIDs :: [(String,Namespace)]
+nsIDs = [
+ ("urn:oasis:names:tc:opendocument:xmlns:animation" , NsAnim ),
+ ("urn:oasis:names:tc:opendocument:xmlns:chart" , NsChart ),
+ ("urn:oasis:names:tc:opendocument:xmlns:config" , NsConfig ),
+ ("urn:oasis:names:tc:opendocument:xmlns:database" , NsDB ),
+ ("urn:oasis:names:tc:opendocument:xmlns:dr3d" , Ns3D ),
+ ("urn:oasis:names:tc:opendocument:xmlns:drawing" , NsDraw ),
+ ("urn:oasis:names:tc:opendocument:xmlns:form" , NsForm ),
+ ("urn:oasis:names:tc:opendocument:xmlns:manifest" , NsManifest ),
+ ("urn:oasis:names:tc:opendocument:xmlns:meta" , NsMeta ),
+ ("urn:oasis:names:tc:opendocument:xmlns:datastyle" , NsNumber ),
+ ("urn:oasis:names:tc:opendocument:xmlns:of" , NsOpenFormula ),
+ ("urn:oasis:names:tc:opendocument:xmlns:office:1.0" , NsOffice ),
+ ("urn:oasis:names:tc:opendocument:xmlns:presentation" , NsPresentation ),
+ ("urn:oasis:names:tc:opendocument:xmlns:script" , NsScript ),
+ ("urn:oasis:names:tc:opendocument:xmlns:style" , NsStyle ),
+ ("urn:oasis:names:tc:opendocument:xmlns:table" , NsTable ),
+ ("urn:oasis:names:tc:opendocument:xmlns:text" , NsText ),
+ ("urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible", NsXSL_FO ),
+ ("urn:oasis:names:tc:opendocument:xmlns:smil-compatible" , NsSmil ),
+ ("urn:oasis:names:tc:opendocument:xmlns:svg-compatible" , NsSVG ),
+ ("http://docs.oasis-open.org/ns/office/1.2/meta/odf" , NsODF ),
+ ("http://docs.oasis-open.org/ns/office/1.2/meta/pkg" , NsPKG ),
+ ("http://purl.org/dc/elements" , NsDublinCore ),
+ ("http://www.w3.org/2003/g/data-view" , NsGRDDL ),
+ ("http://www.w3.org/1998/Math/MathML" , NsMathML ),
+ ("http://www.w3.org/1999/xhtml" , NsXHtml ),
+ ("http://www.w3.org/2002/xforms" , NsXForms ),
+ ("http://www.w3.org/1999/xlink" , NsXLink )
+ ] \ No newline at end of file
diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
new file mode 100644
index 000000000..1cf87cc59
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
@@ -0,0 +1,737 @@
+{-# LANGUAGE TupleSections #-}
+{-# LANGUAGE PatternGuards #-}
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE Arrows #-}
+
+{-
+Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.Odt.StyleReader
+ Copyright : Copyright (C) 2015 Martin Linnemann
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Martin Linnemann <theCodingMarlin@googlemail.com>
+ Stability : alpha
+ Portability : portable
+
+Reader for the style information in an odt document.
+-}
+
+module Text.Pandoc.Readers.Odt.StyleReader
+( Style (..)
+, StyleName
+, StyleFamily (..)
+, Styles (..)
+, StyleProperties (..)
+, TextProperties (..)
+, ParaProperties (..)
+, VerticalTextPosition (..)
+, ListItemNumberFormat (..)
+, ListLevel
+, ListStyle (..)
+, ListLevelStyle (..)
+, ListLevelType (..)
+, LengthOrPercent (..)
+, lookupStyle
+, getTextProperty
+, getTextProperty'
+, getParaProperty
+, getListStyle
+, getListLevelStyle
+, getStyleFamily
+, lookupDefaultStyle
+, lookupDefaultStyle'
+, lookupListStyleByName
+, getPropertyChain
+, textPropertyChain
+, stylePropertyChain
+, stylePropertyChain'
+, getStylePropertyChain
+, extendedStylePropertyChain
+, extendedStylePropertyChain'
+, liftStyles
+, readStylesAt
+) where
+
+import Control.Arrow
+import Control.Applicative hiding ( liftA, liftA2, liftA3 )
+
+import qualified Data.Foldable as F
+import qualified Data.Map as M
+import qualified Data.Set as S
+import Data.List ( unfoldr )
+import Data.Default
+import Data.Monoid
+import Data.Maybe
+
+import qualified Text.XML.Light as XML
+
+import Text.Pandoc.Readers.Odt.Arrows.State
+import Text.Pandoc.Readers.Odt.Arrows.Utils
+
+import Text.Pandoc.Readers.Odt.Generic.Utils
+import qualified Text.Pandoc.Readers.Odt.Generic.SetMap as SM
+import Text.Pandoc.Readers.Odt.Generic.Fallible
+import Text.Pandoc.Readers.Odt.Generic.XMLConverter
+
+import Text.Pandoc.Readers.Odt.Namespaces
+import Text.Pandoc.Readers.Odt.Base
+
+
+readStylesAt :: XML.Element -> Fallible Styles
+readStylesAt e = runConverter' readAllStyles mempty e
+
+--------------------------------------------------------------------------------
+-- Reader for font declarations and font pitches
+--------------------------------------------------------------------------------
+
+-- Pandoc has no support for different font pitches. Yet knowing them can be
+-- very helpful in cases where Pandoc has more semantics than OpenDocument.
+-- In these cases, the pitch can help deciding as what to define a block of
+-- text. So let's start with a type for font pitches:
+
+data FontPitch = PitchVariable | PitchFixed
+ deriving ( Eq, Show )
+
+instance Lookupable FontPitch where
+ lookupTable = [ ("variable" , PitchVariable)
+ , ("fixed" , PitchFixed )
+ ]
+
+instance Default FontPitch where
+ def = PitchVariable
+
+-- The font pitch can be specifed in a style directly. Normally, however,
+-- it is defined in the font. That is also the specs' recommendation.
+--
+-- Thus, we want
+
+type FontFaceName = String
+
+type FontPitches = M.Map FontFaceName FontPitch
+
+-- To get there, the fonts have to be read and the pitches extracted.
+-- But the resulting map are only needed at one later place, so it should not be
+-- transported on the value level, especially as we already use a state arrow.
+-- So instead, the resulting map is lifted into the state of the reader.
+-- (An alternative might be ImplicitParams, but again, we already have a state.)
+--
+-- So the main style readers will have the types
+type StyleReader a b = XMLReader FontPitches a b
+-- and
+type StyleReaderSafe a b = XMLReaderSafe FontPitches a b
+-- respectively.
+--
+-- But before we can work with these, we need to define the reader that reads
+-- the fonts:
+
+-- | A reader for font pitches
+fontPitchReader :: XMLReader _s _x FontPitches
+fontPitchReader = executeIn NsOffice "font-face-decls" (
+ ( withEveryL NsStyle "font-face" $ liftAsSuccess (
+ findAttr' NsStyle "name"
+ &&&
+ lookupDefaultingAttr NsStyle "font-pitch"
+ )
+ )
+ >>?^ ( M.fromList . (foldl accumLegalPitches []) )
+ )
+ where accumLegalPitches ls (Nothing,_) = ls
+ accumLegalPitches ls (Just n,p) = (n,p):ls
+
+
+-- | A wrapper around the font pitch reader that lifts the result into the
+-- state.
+readFontPitches :: StyleReader x x
+readFontPitches = producingExtraState () () fontPitchReader
+
+
+-- | Looking up a pitch in the state of the arrow.
+--
+-- The function does the following:
+-- * Look for the font pitch in an attribute.
+-- * If that fails, look for the font name, look up the font in the state
+-- and use the pitch from there.
+-- * Return the result in a Maybe
+--
+findPitch :: XMLReaderSafe FontPitches _x (Maybe FontPitch)
+findPitch = ( lookupAttr NsStyle "font-pitch"
+ `ifFailedDo` findAttr NsStyle "font-name"
+ >>? ( keepingTheValue getExtraState
+ >>§ M.lookup
+ >>^ maybeToChoice
+ )
+ )
+ >>> choiceToMaybe
+
+--------------------------------------------------------------------------------
+-- Definitions of main data
+--------------------------------------------------------------------------------
+
+type StyleName = String
+
+-- | There are two types of styles: named styles with a style family and an
+-- optional style parent, and default styles for each style family,
+-- defining default style properties
+data Styles = Styles
+ { stylesByName :: M.Map StyleName Style
+ , listStylesByName :: M.Map StyleName ListStyle
+ , defaultStyleMap :: M.Map StyleFamily StyleProperties
+ }
+ deriving ( Show )
+
+-- Styles from a monoid under union
+instance Monoid Styles where
+ mempty = Styles M.empty M.empty M.empty
+ mappend (Styles sBn1 dSm1 lsBn1)
+ (Styles sBn2 dSm2 lsBn2)
+ = Styles (M.union sBn1 sBn2)
+ (M.union dSm1 dSm2)
+ (M.union lsBn1 lsBn2)
+
+-- Not all families from the specifications are implemented, only those we need.
+-- But there are none that are not mentioned here.
+data StyleFamily = FaText | FaParagraph
+-- | FaTable | FaTableCell | FaTableColumn | FaTableRow
+-- | FaGraphic | FaDrawing | FaChart
+-- | FaPresentation
+-- | FaRuby
+ deriving ( Eq, Ord, Show )
+
+instance Lookupable StyleFamily where
+ lookupTable = [ ( "text" , FaText )
+ , ( "paragraph" , FaParagraph )
+-- , ( "table" , FaTable )
+-- , ( "table-cell" , FaTableCell )
+-- , ( "table-column" , FaTableColumn )
+-- , ( "table-row" , FaTableRow )
+-- , ( "graphic" , FaGraphic )
+-- , ( "drawing-page" , FaDrawing )
+-- , ( "chart" , FaChart )
+-- , ( "presentation" , FaPresentation )
+-- , ( "ruby" , FaRuby )
+ ]
+
+-- | A named style
+data Style = Style { styleFamily :: Maybe StyleFamily
+ , styleParentName :: Maybe StyleName
+ , listStyle :: Maybe StyleName
+ , styleProperties :: StyleProperties
+ }
+ deriving ( Eq, Show )
+
+data StyleProperties = SProps { textProperties :: Maybe TextProperties
+ , paraProperties :: Maybe ParaProperties
+-- , tableColProperties :: Maybe TColProperties
+-- , tableRowProperties :: Maybe TRowProperties
+-- , tableCellProperties :: Maybe TCellProperties
+-- , tableProperties :: Maybe TableProperties
+-- , graphicProperties :: Maybe GraphProperties
+ }
+ deriving ( Eq, Show )
+
+instance Default StyleProperties where
+ def = SProps { textProperties = Just def
+ , paraProperties = Just def
+ }
+
+data TextProperties = PropT { isEmphasised :: Bool
+ , isStrong :: Bool
+ , pitch :: Maybe FontPitch
+ , verticalPosition :: VerticalTextPosition
+ , underline :: Maybe UnderlineMode
+ , strikethrough :: Maybe UnderlineMode
+ }
+ deriving ( Eq, Show )
+
+instance Default TextProperties where
+ def = PropT { isEmphasised = False
+ , isStrong = False
+ , pitch = Just def
+ , verticalPosition = def
+ , underline = Nothing
+ , strikethrough = Nothing
+ }
+
+data ParaProperties = PropP { paraNumbering :: ParaNumbering
+ , indentation :: LengthOrPercent
+ , margin_left :: LengthOrPercent
+ }
+ deriving ( Eq, Show )
+
+instance Default ParaProperties where
+ def = PropP { paraNumbering = NumberingNone
+ , indentation = def
+ , margin_left = def
+ }
+
+----
+-- All the little data types that make up the properties
+----
+
+data VerticalTextPosition = VPosNormal | VPosSuper | VPosSub
+ deriving ( Eq, Show )
+
+instance Default VerticalTextPosition where
+ def = VPosNormal
+
+instance Read VerticalTextPosition where
+ readsPrec _ s = [ (VPosSub , s') | ("sub" , s') <- lexS ]
+ ++ [ (VPosSuper , s') | ("super" , s') <- lexS ]
+ ++ [ (signumToVPos n , s') | ( n , s') <- readPercent s ]
+ where
+ lexS = lex s
+ signumToVPos n | n < 0 = VPosSub
+ | n > 0 = VPosSuper
+ | otherwise = VPosNormal
+
+data UnderlineMode = UnderlineModeNormal | UnderlineModeSkipWhitespace
+ deriving ( Eq, Show )
+
+instance Lookupable UnderlineMode where
+ lookupTable = [ ( "continuous" , UnderlineModeNormal )
+ , ( "skip-white-space" , UnderlineModeSkipWhitespace )
+ ]
+
+
+data ParaNumbering = NumberingNone | NumberingKeep | NumberingRestart Int
+ deriving ( Eq, Show )
+
+data LengthOrPercent = LengthValueMM Int | PercentValue Int
+ deriving ( Eq, Show )
+
+instance Default LengthOrPercent where
+ def = LengthValueMM 0
+
+instance Read LengthOrPercent where
+ readsPrec _ s =
+ [ (PercentValue percent , s' ) | (percent , s' ) <- readPercent s]
+ ++ [ (LengthValueMM lengthMM , s'') | (length' , s' ) <- reads s
+ , (unit , s'') <- reads s'
+ , let lengthMM = estimateInMillimeter
+ length' unit
+ ]
+
+data XslUnit = XslUnitMM | XslUnitCM
+ | XslUnitInch
+ | XslUnitPoints | XslUnitPica
+ | XslUnitPixel
+ | XslUnitEM
+
+instance Show XslUnit where
+ show XslUnitMM = "mm"
+ show XslUnitCM = "cm"
+ show XslUnitInch = "in"
+ show XslUnitPoints = "pt"
+ show XslUnitPica = "pc"
+ show XslUnitPixel = "px"
+ show XslUnitEM = "em"
+
+instance Read XslUnit where
+ readsPrec _ "mm" = [(XslUnitMM , "")]
+ readsPrec _ "cm" = [(XslUnitCM , "")]
+ readsPrec _ "in" = [(XslUnitInch , "")]
+ readsPrec _ "pt" = [(XslUnitPoints , "")]
+ readsPrec _ "pc" = [(XslUnitPica , "")]
+ readsPrec _ "px" = [(XslUnitPixel , "")]
+ readsPrec _ "em" = [(XslUnitEM , "")]
+ readsPrec _ _ = []
+
+-- | Rough conversion of measures into millimeters.
+-- Pixels and em's are actually implemetation dependant/relative measures,
+-- so I could not really easily calculate anything exact here even if I wanted.
+-- But I do not care about exactness right now, as I only use measures
+-- to determine if a paragraph is "indented" or not.
+estimateInMillimeter :: Int -> XslUnit -> Int
+estimateInMillimeter n XslUnitMM = n
+estimateInMillimeter n XslUnitCM = n * 10
+estimateInMillimeter n XslUnitInch = n * 25 -- * 25.4
+estimateInMillimeter n XslUnitPoints = n `div` 3 -- * 1/72 * 25.4
+estimateInMillimeter n XslUnitPica = n * 4 -- * 12 * 1/72 * 25.4
+estimateInMillimeter n XslUnitPixel = n `div`3 -- * 1/72 * 25.4
+estimateInMillimeter n XslUnitEM = n * 7 -- * 16 * 1/72 * 25.4
+
+
+----
+-- List styles
+----
+
+type ListLevel = Int
+
+newtype ListStyle = ListStyle { levelStyles :: M.Map ListLevel ListLevelStyle
+ }
+ deriving ( Eq, Show )
+
+--
+getListLevelStyle :: ListLevel -> ListStyle -> Maybe ListLevelStyle
+getListLevelStyle level ListStyle{..} =
+ let (lower , exactHit , _) = M.splitLookup level levelStyles
+ in exactHit <|> fmap fst (M.maxView lower)
+ -- findBy (`M.lookup` levelStyles) [level, (level-1) .. 1]
+ -- ^ simpler, but in general less efficient
+
+data ListLevelStyle = ListLevelStyle { listLevelType :: ListLevelType
+ , listItemPrefix :: Maybe String
+ , listItemSuffix :: Maybe String
+ , listItemFormat :: ListItemNumberFormat
+ }
+ deriving ( Eq, Ord )
+
+instance Show ListLevelStyle where
+ show ListLevelStyle{..} = "<LLS|"
+ ++ (show listLevelType)
+ ++ "|"
+ ++ (maybeToString listItemPrefix)
+ ++ (show listItemFormat)
+ ++ (maybeToString listItemSuffix)
+ ++ ">"
+ where maybeToString = fromMaybe ""
+
+data ListLevelType = LltBullet | LltImage | LltNumbered
+ deriving ( Eq, Ord, Show )
+
+data ListItemNumberFormat = LinfNone
+ | LinfNumber
+ | LinfRomanLC | LinfRomanUC
+ | LinfAlphaLC | LinfAlphaUC
+ | LinfString String
+ deriving ( Eq, Ord )
+
+instance Show ListItemNumberFormat where
+ show LinfNone = ""
+ show LinfNumber = "1"
+ show LinfRomanLC = "i"
+ show LinfRomanUC = "I"
+ show LinfAlphaLC = "a"
+ show LinfAlphaUC = "A"
+ show (LinfString s) = s
+
+instance Default ListItemNumberFormat where
+ def = LinfNone
+
+instance Read ListItemNumberFormat where
+ readsPrec _ "" = [(LinfNone , "")]
+ readsPrec _ "1" = [(LinfNumber , "")]
+ readsPrec _ "i" = [(LinfRomanLC , "")]
+ readsPrec _ "I" = [(LinfRomanUC , "")]
+ readsPrec _ "a" = [(LinfAlphaLC , "")]
+ readsPrec _ "A" = [(LinfAlphaUC , "")]
+ readsPrec _ s = [(LinfString s , "")]
+
+--------------------------------------------------------------------------------
+-- Readers
+--
+-- ...it seems like a whole lot of this should be automatically deriveable
+-- or at least moveable into a class. Most of this is data concealed in
+-- code.
+--------------------------------------------------------------------------------
+
+--
+readAllStyles :: StyleReader _x Styles
+readAllStyles = ( readFontPitches
+ >>?! ( readAutomaticStyles
+ &&& readStyles ))
+ >>?§? chooseMax
+ -- all top elements are always on the same hierarchy level
+
+--
+readStyles :: StyleReader _x Styles
+readStyles = executeIn NsOffice "styles" $ liftAsSuccess
+ $ liftA3 Styles
+ ( tryAll NsStyle "style" readStyle >>^ M.fromList )
+ ( tryAll NsText "list-style" readListStyle >>^ M.fromList )
+ ( tryAll NsStyle "default-style" readDefaultStyle >>^ M.fromList )
+
+--
+readAutomaticStyles :: StyleReader _x Styles
+readAutomaticStyles = executeIn NsOffice "automatic-styles" $ liftAsSuccess
+ $ liftA3 Styles
+ ( tryAll NsStyle "style" readStyle >>^ M.fromList )
+ ( tryAll NsText "list-style" readListStyle >>^ M.fromList )
+ ( returnV M.empty )
+
+--
+readDefaultStyle :: StyleReader _x (StyleFamily, StyleProperties)
+readDefaultStyle = lookupAttr NsStyle "family"
+ >>?! keepingTheValue readStyleProperties
+
+--
+readStyle :: StyleReader _x (StyleName,Style)
+readStyle = findAttr NsStyle "name"
+ >>?! keepingTheValue
+ ( liftA4 Style
+ ( lookupAttr' NsStyle "family" )
+ ( findAttr' NsStyle "parent-style-name" )
+ ( findAttr' NsStyle "list-style-name" )
+ readStyleProperties
+ )
+
+--
+readStyleProperties :: StyleReaderSafe _x StyleProperties
+readStyleProperties = liftA2 SProps
+ ( readTextProperties >>> choiceToMaybe )
+ ( readParaProperties >>> choiceToMaybe )
+
+--
+readTextProperties :: StyleReader _x TextProperties
+readTextProperties =
+ executeIn NsStyle "text-properties" $ liftAsSuccess
+ ( liftA6 PropT
+ ( searchAttr NsXSL_FO "font-style" False isFontEmphasised )
+ ( searchAttr NsXSL_FO "font-weight" False isFontBold )
+ ( findPitch )
+ ( getAttr NsStyle "text-position" )
+ ( readUnderlineMode )
+ ( readStrikeThroughMode )
+ )
+ where isFontEmphasised = [("normal",False),("italic",True),("oblique",True)]
+ isFontBold = ("normal",False):("bold",True)
+ :(map ((,True).show) ([100,200..900]::[Int]))
+
+readUnderlineMode :: StyleReaderSafe _x (Maybe UnderlineMode)
+readUnderlineMode = readLineMode "text-underline-mode"
+ "text-underline-style"
+
+readStrikeThroughMode :: StyleReaderSafe _x (Maybe UnderlineMode)
+readStrikeThroughMode = readLineMode "text-line-through-mode"
+ "text-line-through-style"
+
+readLineMode :: String -> String -> StyleReaderSafe _x (Maybe UnderlineMode)
+readLineMode modeAttr styleAttr = proc x -> do
+ isUL <- searchAttr NsStyle styleAttr False isLinePresent -< x
+ mode <- lookupAttr' NsStyle modeAttr -< x
+ if isUL
+ then case mode of
+ Just m -> returnA -< Just m
+ Nothing -> returnA -< Just UnderlineModeNormal
+ else returnA -< Nothing
+ where
+ isLinePresent = [("none",False)] ++ map (,True)
+ [ "dash" , "dot-dash" , "dot-dot-dash" , "dotted"
+ , "long-dash" , "solid" , "wave"
+ ]
+
+--
+readParaProperties :: StyleReader _x ParaProperties
+readParaProperties =
+ executeIn NsStyle "paragraph-properties" $ liftAsSuccess
+ ( liftA3 PropP
+ ( liftA2 readNumbering
+ ( isSet' NsText "number-lines" )
+ ( readAttr' NsText "line-number" )
+ )
+ ( liftA2 readIndentation
+ ( isSetWithDefault NsStyle "auto-text-indent" False )
+ ( getAttr NsXSL_FO "text-indent" )
+ )
+ ( getAttr NsXSL_FO "margin-left" )
+ )
+ where readNumbering (Just True) (Just n) = NumberingRestart n
+ readNumbering (Just True) _ = NumberingKeep
+ readNumbering _ _ = NumberingNone
+
+ readIndentation False indent = indent
+ readIndentation True _ = def
+
+----
+-- List styles
+----
+
+--
+readListStyle :: StyleReader _x (StyleName, ListStyle)
+readListStyle =
+ findAttr NsStyle "name"
+ >>?! keepingTheValue
+ ( liftA ListStyle
+ $ ( liftA3 SM.union3
+ ( readListLevelStyles NsText "list-level-style-number" LltNumbered )
+ ( readListLevelStyles NsText "list-level-style-bullet" LltBullet )
+ ( readListLevelStyles NsText "list-level-style-image" LltImage )
+ ) >>^ M.mapMaybe chooseMostSpecificListLevelStyle
+ )
+--
+readListLevelStyles :: Namespace -> ElementName
+ -> ListLevelType
+ -> StyleReaderSafe _x (SM.SetMap Int ListLevelStyle)
+readListLevelStyles namespace elementName levelType =
+ ( tryAll namespace elementName (readListLevelStyle levelType)
+ >>^ SM.fromList
+ )
+
+--
+readListLevelStyle :: ListLevelType -> StyleReader _x (Int, ListLevelStyle)
+readListLevelStyle levelType = readAttr NsText "level"
+ >>?! keepingTheValue
+ ( liftA4 toListLevelStyle
+ ( returnV levelType )
+ ( findAttr' NsStyle "num-prefix" )
+ ( findAttr' NsStyle "num-suffix" )
+ ( getAttr NsStyle "num-format" )
+ )
+ where
+ toListLevelStyle _ p s LinfNone = ListLevelStyle LltBullet p s LinfNone
+ toListLevelStyle _ p s f@(LinfString _) = ListLevelStyle LltBullet p s f
+ toListLevelStyle t p s f = ListLevelStyle t p s f
+
+--
+chooseMostSpecificListLevelStyle :: S.Set ListLevelStyle -> Maybe ListLevelStyle
+chooseMostSpecificListLevelStyle ls | ls == mempty = Nothing
+ | otherwise = Just ( F.foldr1 select ls )
+ where
+ select ( ListLevelStyle t1 p1 s1 f1 )
+ ( ListLevelStyle t2 p2 s2 f2 )
+ = ListLevelStyle (select' t1 t2) (p1 <|> p2) (s1 <|> s2) (selectLinf f1 f2)
+ select' LltNumbered _ = LltNumbered
+ select' _ LltNumbered = LltNumbered
+ select' _ _ = LltBullet
+ selectLinf LinfNone f2 = f2
+ selectLinf f1 LinfNone = f1
+ selectLinf (LinfString _) f2 = f2
+ selectLinf f1 (LinfString _) = f1
+ selectLinf f1 _ = f1
+
+
+--------------------------------------------------------------------------------
+-- Tools to access style data
+--------------------------------------------------------------------------------
+
+--
+lookupStyle :: StyleName -> Styles -> Maybe Style
+lookupStyle name Styles{..} = M.lookup name stylesByName
+
+--
+lookupDefaultStyle :: StyleFamily -> Styles -> StyleProperties
+lookupDefaultStyle family Styles{..} = fromMaybe def
+ (M.lookup family defaultStyleMap)
+
+--
+lookupDefaultStyle' :: Styles -> StyleFamily -> StyleProperties
+lookupDefaultStyle' Styles{..} family = fromMaybe def
+ (M.lookup family defaultStyleMap)
+
+--
+getListStyle :: Style -> Styles -> Maybe ListStyle
+getListStyle Style{..} styles = listStyle >>= (`lookupListStyleByName` styles)
+
+--
+lookupListStyleByName :: StyleName -> Styles -> Maybe ListStyle
+lookupListStyleByName name Styles{..} = M.lookup name listStylesByName
+
+
+-- | Returns a chain of parent of the current style. The direct parent will
+-- be the first element of the list, followed by its parent and so on.
+-- The current style is not in the list.
+parents :: Style -> Styles -> [Style]
+parents style styles = unfoldr findNextParent style -- Ha!
+ where findNextParent Style{..}
+ = fmap duplicate $ (`lookupStyle` styles) =<< styleParentName
+
+-- | Looks up the style family of the current style. Normally, every style
+-- should have one. But if not, all parents are searched.
+getStyleFamily :: Style -> Styles -> Maybe StyleFamily
+getStyleFamily style@Style{..} styles
+ = styleFamily
+ <|> (F.asum $ map (`getStyleFamily` styles) $ parents style styles)
+
+-- | Each 'Style' has certain 'StyleProperties'. But sometimes not all property
+-- values are specified. Instead, a value might be inherited from a
+-- parent style. This function makes this chain of inheritance
+-- concrete and easily accessible by encapsulating the necessary lookups.
+-- The resulting list contains the direct properties of the style as the first
+-- element, the ones of the direct parent element as the next one, and so on.
+--
+-- Note: There should also be default properties for each style family. These
+-- are @not@ contained in this list because properties inherited from
+-- parent elements take precedence over default styles.
+--
+-- This function is primarily meant to be used through convenience wrappers.
+--
+stylePropertyChain :: Style -> Styles -> [StyleProperties]
+stylePropertyChain style styles
+ = map styleProperties (style : parents style styles)
+
+--
+extendedStylePropertyChain :: [Style] -> Styles -> [StyleProperties]
+extendedStylePropertyChain [] _ = []
+extendedStylePropertyChain [style] styles = (stylePropertyChain style styles)
+ ++ (maybeToList (fmap (lookupDefaultStyle' styles) (getStyleFamily style styles)))
+extendedStylePropertyChain (style:trace) styles = (stylePropertyChain style styles)
+ ++ (extendedStylePropertyChain trace styles)
+-- Optimizable with Data.Sequence
+
+--
+extendedStylePropertyChain' :: [Style] -> Styles -> Maybe [StyleProperties]
+extendedStylePropertyChain' [] _ = Nothing
+extendedStylePropertyChain' [style] styles = Just (
+ (stylePropertyChain style styles)
+ ++ (maybeToList (fmap (lookupDefaultStyle' styles) (getStyleFamily style styles)))
+ )
+extendedStylePropertyChain' (style:trace) styles = fmap ((stylePropertyChain style styles) ++)
+ (extendedStylePropertyChain' trace styles)
+
+--
+stylePropertyChain' :: Styles -> Style -> [StyleProperties]
+stylePropertyChain' = flip stylePropertyChain
+
+--
+getStylePropertyChain :: StyleName -> Styles -> [StyleProperties]
+getStylePropertyChain name styles = maybe []
+ (`stylePropertyChain` styles)
+ (lookupStyle name styles)
+
+--
+getPropertyChain :: (StyleProperties -> Maybe a) -> Style -> Styles -> [a]
+getPropertyChain extract style styles = catMaybes
+ $ map extract
+ $ stylePropertyChain style styles
+
+--
+textPropertyChain :: Style -> Styles -> [TextProperties]
+textPropertyChain = getPropertyChain textProperties
+
+--
+paraPropertyChain :: Style -> Styles -> [ParaProperties]
+paraPropertyChain = getPropertyChain paraProperties
+
+--
+getTextProperty :: (TextProperties -> a) -> Style -> Styles -> Maybe a
+getTextProperty extract style styles = fmap extract
+ $ listToMaybe
+ $ textPropertyChain style styles
+
+--
+getTextProperty' :: (TextProperties -> Maybe a) -> Style -> Styles -> Maybe a
+getTextProperty' extract style styles = F.asum
+ $ map extract
+ $ textPropertyChain style styles
+
+--
+getParaProperty :: (ParaProperties -> a) -> Style -> Styles -> Maybe a
+getParaProperty extract style styles = fmap extract
+ $ listToMaybe
+ $ paraPropertyChain style styles
+
+-- | Lifts the reader into another readers' state.
+liftStyles :: (OdtConverterState s -> OdtConverterState Styles)
+ -> (OdtConverterState Styles -> OdtConverterState s )
+ -> XMLReader s x x
+liftStyles extract inject = switchState extract inject
+ $ convertingExtraState M.empty readAllStyles
+
diff --git a/src/Text/Pandoc/Readers/Org.hs b/src/Text/Pandoc/Readers/Org.hs
index 5c00a1b27..980f63504 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,7 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances #-}
{-
-Copyright (C) 2014 Albert Krewinkel <tarleb@moltkeplatz.de>
+Copyright (C) 2014-2015 Albert Krewinkel <tarleb@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -42,12 +43,13 @@ import Text.Pandoc.Parsing hiding ( F, unF, askF, asksF, runF
import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
import Text.Pandoc.Shared (compactify', compactify'DL)
import Text.TeXMath (readTeX, writePandoc, DisplayType(..))
+import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
import Control.Applicative ( Applicative, pure
, (<$>), (<$), (<*>), (<*), (*>) )
import Control.Arrow (first)
import Control.Monad (foldM, guard, liftM, liftM2, mplus, mzero, when)
-import Control.Monad.Reader (Reader, runReader, ask, asks)
+import Control.Monad.Reader (Reader, runReader, ask, asks, local)
import Data.Char (isAlphaNum, toLower)
import Data.Default
import Data.List (intersperse, isPrefixOf, isSuffixOf)
@@ -56,20 +58,57 @@ import Data.Maybe (fromMaybe, isJust)
import Data.Monoid (Monoid, mconcat, mempty, mappend)
import Network.HTTP (urlEncode)
+import Text.Pandoc.Error
+
-- | Parse org-mode string and return a Pandoc document.
readOrg :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
-readOrg opts s = readWith parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
+ -> Either PandocError Pandoc
+readOrg opts s = flip runReader def $ readWithM parseOrg def{ orgStateOptions = opts } (s ++ "\n\n")
+
+data OrgParserLocal = OrgParserLocal { orgLocalQuoteContext :: QuoteContext }
-type OrgParser = Parser [Char] OrgParserState
+type OrgParser = ParserT [Char] OrgParserState (Reader OrgParserLocal)
parseOrg :: OrgParser Pandoc
parseOrg = do
blocks' <- parseBlocks
st <- getState
let meta = runF (orgStateMeta' st) st
- return $ Pandoc meta $ filter (/= Null) (B.toList $ runF blocks' st)
+ let removeUnwantedBlocks = dropCommentTrees . filter (/= Null)
+ return $ Pandoc meta $ removeUnwantedBlocks (B.toList $ runF blocks' st)
+
+-- | Drop COMMENT headers and the document tree below those headers.
+dropCommentTrees :: [Block] -> [Block]
+dropCommentTrees [] = []
+dropCommentTrees blks@(b:bs) =
+ maybe blks (flip dropUntilHeaderAboveLevel bs) $ commentHeaderLevel b
+
+-- | Return the level of a header starting a comment or :noexport: tree and
+-- Nothing otherwise.
+commentHeaderLevel :: Block -> Maybe Int
+commentHeaderLevel blk =
+ case blk of
+ (Header level _ ((Str "COMMENT"):_)) -> Just level
+ (Header level _ title) | hasNoExportTag title -> Just level
+ _ -> Nothing
+ where
+ hasNoExportTag :: [Inline] -> Bool
+ hasNoExportTag = any isNoExportTag
+
+ isNoExportTag :: Inline -> Bool
+ isNoExportTag (Span ("", ["tag"], [("data-tag-name", "noexport")]) []) = True
+ isNoExportTag _ = False
+
+-- | Drop blocks until a header on or above the given level is seen
+dropUntilHeaderAboveLevel :: Int -> [Block] -> [Block]
+dropUntilHeaderAboveLevel n = dropWhile (not . isHeaderLevelLowerEq n)
+
+isHeaderLevelLowerEq :: Int -> Block -> Bool
+isHeaderLevelLowerEq n blk =
+ case blk of
+ (Header level _ _) -> n >= level
+ _ -> False
--
-- Parser State for Org
@@ -98,6 +137,9 @@ data OrgParserState = OrgParserState
, orgStateNotes' :: OrgNoteTable
}
+instance Default OrgParserLocal where
+ def = OrgParserLocal NoQuote
+
instance HasReaderOptions OrgParserState where
extractReaderOptions = orgStateOptions
@@ -111,6 +153,10 @@ instance HasLastStrPosition OrgParserState where
getLastStrPos = orgStateLastStrPos
setLastStrPos pos st = st{ orgStateLastStrPos = Just pos }
+instance HasQuoteContext st (Reader OrgParserLocal) where
+ getQuoteContext = asks orgLocalQuoteContext
+ withQuoteContext q = local (\s -> s{orgLocalQuoteContext = q})
+
instance Default OrgParserState where
def = defaultOrgParserState
@@ -134,19 +180,6 @@ recordAnchorId :: String -> OrgParser ()
recordAnchorId i = updateState $ \s ->
s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
-addBlockAttribute :: String -> String -> OrgParser ()
-addBlockAttribute key val = updateState $ \s ->
- let attrs = orgStateBlockAttributes s
- in s{ orgStateBlockAttributes = M.insert key val attrs }
-
-lookupBlockAttribute :: String -> OrgParser (Maybe String)
-lookupBlockAttribute key =
- M.lookup key . orgStateBlockAttributes <$> getState
-
-resetBlockAttributes :: OrgParser ()
-resetBlockAttributes = updateState $ \s ->
- s{ orgStateBlockAttributes = orgStateBlockAttributes def }
-
updateLastForbiddenCharPos :: OrgParser ()
updateLastForbiddenCharPos = getPosition >>= \p ->
updateState $ \s -> s{ orgStateLastForbiddenCharPos = Just p}
@@ -274,9 +307,18 @@ block = choice [ mempty <$ blanklines
, paraOrPlain
] <?> "block"
+--
+-- Block Attributes
+--
+
+-- | Parse optional block attributes (like #+TITLE or #+NAME)
optionalAttributes :: OrgParser (F Blocks) -> OrgParser (F Blocks)
optionalAttributes parser = try $
resetBlockAttributes *> parseBlockAttributes *> parser
+ where
+ resetBlockAttributes :: OrgParser ()
+ resetBlockAttributes = updateState $ \s ->
+ s{ orgStateBlockAttributes = orgStateBlockAttributes def }
parseBlockAttributes :: OrgParser ()
parseBlockAttributes = do
@@ -301,6 +343,15 @@ lookupInlinesAttr attr = try $ do
(fmap Just . parseFromString parseInlines)
val
+addBlockAttribute :: String -> String -> OrgParser ()
+addBlockAttribute key val = updateState $ \s ->
+ let attrs = orgStateBlockAttributes s
+ in s{ orgStateBlockAttributes = M.insert key val attrs }
+
+lookupBlockAttribute :: String -> OrgParser (Maybe String)
+lookupBlockAttribute key =
+ M.lookup key . orgStateBlockAttributes <$> getState
+
--
-- Org Blocks (#+BEGIN_... / #+END_...)
@@ -356,11 +407,11 @@ exportsResults :: [(String, String)] -> Bool
exportsResults attrs = ("rundoc-exports", "results") `elem` attrs
|| ("rundoc-exports", "both") `elem` attrs
-followingResultsBlock :: OrgParser (Maybe String)
+followingResultsBlock :: OrgParser (Maybe (F Blocks))
followingResultsBlock =
optionMaybe (try $ blanklines *> stringAnyCase "#+RESULTS:"
*> blankline
- *> (unlines <$> many1 exampleLine))
+ *> block)
codeBlock :: BlockProperties -> OrgParser (F Blocks)
codeBlock blkProp = do
@@ -375,7 +426,7 @@ codeBlock blkProp = do
labelledBlck <- maybe (pure codeBlck)
(labelDiv codeBlck)
<$> lookupInlinesAttr "caption"
- let resultBlck = pure $ maybe mempty (exampleCode) resultsContent
+ let resultBlck = fromMaybe mempty resultsContent
return $ (if includeCode then labelledBlck else mempty)
<> (if includeResults then resultBlck else mempty)
where
@@ -614,8 +665,25 @@ parseFormat = try $ do
header :: OrgParser (F Blocks)
header = try $ do
level <- headerStart
- title <- inlinesTillNewline
- return $ B.header level <$> title
+ title <- manyTill inline (lookAhead headerEnd)
+ tags <- headerEnd
+ let inlns = trimInlinesF . mconcat $ title <> map tagToInlineF tags
+ return $ B.header level <$> inlns
+ where
+ tagToInlineF :: String -> F Inlines
+ tagToInlineF t = return $ B.spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
+
+headerEnd :: OrgParser [String]
+headerEnd = option [] headerTags <* newline
+
+headerTags :: OrgParser [String]
+headerTags = try $
+ skipSpaces
+ *> char ':'
+ *> many1 tag
+ <* skipSpaces
+ where tag = many1 (alphaNum <|> oneOf "@%#_")
+ <* char ':'
headerStart :: OrgParser Int
headerStart = try $
@@ -828,12 +896,14 @@ list :: OrgParser (F Blocks)
list = choice [ definitionList, bulletList, orderedList ] <?> "list"
definitionList :: OrgParser (F Blocks)
-definitionList = fmap B.definitionList . fmap compactify'DL . sequence
- <$> many1 (definitionListItem bulletListStart)
+definitionList = try $ do n <- lookAhead (bulletListStart' Nothing)
+ fmap B.definitionList . fmap compactify'DL . sequence
+ <$> many1 (definitionListItem $ bulletListStart' (Just n))
bulletList :: OrgParser (F Blocks)
-bulletList = fmap B.bulletList . fmap compactify' . sequence
- <$> many1 (listItem bulletListStart)
+bulletList = try $ do n <- lookAhead (bulletListStart' Nothing)
+ fmap B.bulletList . fmap compactify' . sequence
+ <$> many1 (listItem (bulletListStart' $ Just n))
orderedList :: OrgParser (F Blocks)
orderedList = fmap B.orderedList . fmap compactify' . sequence
@@ -845,10 +915,27 @@ genericListStart listMarker = try $
(+) <$> (length <$> many spaceChar)
<*> (length <$> listMarker <* many1 spaceChar)
--- parses bullet list start and returns its length (excl. following whitespace)
+-- parses bullet list marker. maybe we know the indent level
bulletListStart :: OrgParser Int
-bulletListStart = genericListStart bulletListMarker
- where bulletListMarker = pure <$> oneOf "*-+"
+bulletListStart = bulletListStart' Nothing
+
+bulletListStart' :: Maybe Int -> OrgParser Int
+-- returns length of bulletList prefix, inclusive of marker
+bulletListStart' Nothing = do ind <- length <$> many spaceChar
+ when (ind == 0) $ notFollowedBy (char '*')
+ oneOf bullets
+ many1 spaceChar
+ return (ind + 1)
+ -- Unindented lists are legal, but they can't use '*' bullets
+ -- We return n to maintain compatibility with the generic listItem
+bulletListStart' (Just n) = do count (n-1) spaceChar
+ when (n == 1) $ notFollowedBy (char '*')
+ oneOf bullets
+ many1 spaceChar
+ return n
+
+bullets :: String
+bullets = "*+-"
orderedListStart :: OrgParser Int
orderedListStart = genericListStart orderedListMarker
@@ -918,6 +1005,7 @@ inline =
, subscript
, superscript
, inlineLaTeX
+ , smart
, symbol
] <* (guard =<< newlinesCountWithinLimits)
<?> "inline"
@@ -927,7 +1015,7 @@ parseInlines = trimInlinesF . mconcat <$> many1 inline
-- treat these as potentially non-text when parsing inline:
specialChars :: [Char]
-specialChars = "\"$'()*+-./:<=>[\\]^_{|}~"
+specialChars = "\"$'()*+-,./:<=>[\\]^_{|}~"
whitespace :: OrgParser (F Inlines)
@@ -1054,13 +1142,13 @@ linkOrImage = explicitOrImageLink
explicitOrImageLink :: OrgParser (F Inlines)
explicitOrImageLink = try $ do
char '['
- srcF <- applyCustomLinkFormat =<< linkTarget
+ srcF <- applyCustomLinkFormat =<< possiblyEmptyLinkTarget
title <- enclosedRaw (char '[') (char ']')
title' <- parseFromString (mconcat <$> many inline) title
char ']'
return $ do
src <- srcF
- if isImageFilename src && isImageFilename title
+ if isImageFilename title
then pure $ B.link src "" $ B.image title mempty mempty
else linkToInlinesF src =<< title'
@@ -1087,6 +1175,9 @@ selfTarget = try $ char '[' *> linkTarget <* char ']'
linkTarget :: OrgParser String
linkTarget = enclosedByPair '[' ']' (noneOf "\n\r[]")
+possiblyEmptyLinkTarget :: OrgParser String
+possiblyEmptyLinkTarget = try linkTarget <|> ("" <$ string "[]")
+
applyCustomLinkFormat :: String -> OrgParser (F String)
applyCustomLinkFormat link = do
let (linkType, rest) = break (== ':') link
@@ -1094,27 +1185,38 @@ applyCustomLinkFormat link = do
formatter <- M.lookup linkType <$> asksF orgStateLinkFormatters
return $ maybe link ($ drop 1 rest) formatter
-
+-- TODO: might be a lot smarter/cleaner to use parsec and ADTs for this kind
+-- of parsing.
linkToInlinesF :: String -> Inlines -> F Inlines
-linkToInlinesF s@('#':_) = pure . B.link s ""
-linkToInlinesF s
- | isImageFilename s = const . pure $ B.image s "" ""
- | isUri s = pure . B.link s ""
- | isRelativeUrl s = pure . B.link s ""
-linkToInlinesF s = \title -> do
- anchorB <- (s `elem`) <$> asksF orgStateAnchorIds
- if anchorB
- then pure $ B.link ('#':s) "" title
- else pure $ B.emph title
-
-isRelativeUrl :: String -> Bool
-isRelativeUrl s = (':' `notElem` s) && ("./" `isPrefixOf` s)
+linkToInlinesF s =
+ case s of
+ "" -> pure . B.link "" ""
+ ('#':_) -> pure . B.link s ""
+ _ | isImageFilename s -> const . pure $ B.image s "" ""
+ _ | isFileLink s -> pure . B.link (dropLinkType s) ""
+ _ | isUri s -> pure . B.link s ""
+ _ | isAbsoluteFilePath s -> pure . B.link ("file://" ++ s) ""
+ _ | isRelativeFilePath s -> pure . B.link s ""
+ _ -> internalLink s
+
+isFileLink :: String -> Bool
+isFileLink s = ("file:" `isPrefixOf` s) && not ("file://" `isPrefixOf` s)
+
+dropLinkType :: String -> String
+dropLinkType = tail . snd . break (== ':')
+
+isRelativeFilePath :: String -> Bool
+isRelativeFilePath s = (("./" `isPrefixOf` s) || ("../" `isPrefixOf` s)) &&
+ (':' `notElem` s)
isUri :: String -> Bool
isUri s = let (scheme, path) = break (== ':') s
- in all (\c -> isAlphaNum c || c `elem` ".-") scheme
+ in all (\c -> isAlphaNum c || c `elem` (".-" :: String)) scheme
&& not (null path)
+isAbsoluteFilePath :: String -> Bool
+isAbsoluteFilePath = ('/' ==) . head
+
isImageFilename :: String -> Bool
isImageFilename filename =
any (\x -> ('.':x) `isSuffixOf` filename) imageExtensions &&
@@ -1124,6 +1226,13 @@ isImageFilename filename =
imageExtensions = [ "jpeg" , "jpg" , "png" , "gif" , "svg" ]
protocols = [ "file", "http", "https" ]
+internalLink :: String -> Inlines -> F Inlines
+internalLink link title = do
+ anchorB <- (link `elem`) <$> asksF orgStateAnchorIds
+ if anchorB
+ then return $ B.link ('#':link) "" title
+ else return $ B.emph title
+
-- | Parse an anchor like @<<anchor-id>>@ and return an empty span with
-- @anchor-id@ set as id. Legal anchors in org-mode are defined through
-- @org-target-regexp@, which is fairly liberal. Since no link is created if
@@ -1148,7 +1257,7 @@ solidify :: String -> String
solidify = map replaceSpecialChar
where replaceSpecialChar c
| isAlphaNum c = c
- | c `elem` "_.-:" = c
+ | c `elem` ("_.-:" :: String) = c
| otherwise = '-'
-- | Parses an inline code block and marks it as an babel block.
@@ -1203,12 +1312,16 @@ displayMath :: OrgParser (F Inlines)
displayMath = return . B.displayMath <$> choice [ rawMathBetween "\\[" "\\]"
, rawMathBetween "$$" "$$"
]
+
+updatePositions :: Char
+ -> OrgParser (Char)
+updatePositions c = do
+ when (c `elem` emphasisPreChars) updateLastPreCharPos
+ when (c `elem` emphasisForbiddenBorderChars) updateLastForbiddenCharPos
+ return c
+
symbol :: OrgParser (F Inlines)
symbol = return . B.str . (: "") <$> (oneOf specialChars >>= updatePositions)
- where updatePositions c
- | c `elem` emphasisPreChars = c <$ updateLastPreCharPos
- | c `elem` emphasisForbiddenBorderChars = c <$ updateLastForbiddenCharPos
- | otherwise = return c
emphasisBetween :: Char
-> OrgParser (F Inlines)
@@ -1387,7 +1500,8 @@ simpleSubOrSuperString = try $
inlineLaTeX :: OrgParser (F Inlines)
inlineLaTeX = try $ do
cmd <- inlineLaTeXCommand
- maybe mzero returnF $ parseAsMath cmd `mplus` parseAsInlineLaTeX cmd
+ maybe mzero returnF $
+ parseAsMath cmd `mplus` parseAsMathMLSym cmd `mplus` parseAsInlineLaTeX cmd
where
parseAsMath :: String -> Maybe Inlines
parseAsMath cs = B.fromList <$> texMathToPandoc cs
@@ -1395,6 +1509,11 @@ inlineLaTeX = try $ do
parseAsInlineLaTeX :: String -> Maybe Inlines
parseAsInlineLaTeX cs = maybeRight $ runParser inlineCommand state "" cs
+ parseAsMathMLSym :: String -> Maybe Inlines
+ parseAsMathMLSym cs = B.str <$> MathMLEntityMap.getUnicode (clean cs)
+ -- dropWhileEnd would be nice here, but it's not available before base 4.5
+ where clean = reverse . dropWhile (`elem` ("{}" :: String)) . reverse . drop 1
+
state :: ParserState
state = def{ stateOptions = def{ readerParseRaw = True }}
@@ -1413,3 +1532,31 @@ inlineLaTeXCommand = try $ do
count len anyChar
return cs
_ -> mzero
+
+smart :: OrgParser (F Inlines)
+smart = do
+ getOption readerSmart >>= guard
+ doubleQuoted <|> singleQuoted <|>
+ choice (map (return <$>) [orgApostrophe, dash, ellipses])
+ where orgApostrophe =
+ (char '\'' <|> char '\8217') <* updateLastPreCharPos
+ <* updateLastForbiddenCharPos
+ *> return (B.str "\x2019")
+
+singleQuoted :: OrgParser (F Inlines)
+singleQuoted = try $ do
+ singleQuoteStart
+ withQuoteContext InSingleQuote $
+ fmap B.singleQuoted . trimInlinesF . mconcat <$>
+ many1Till inline singleQuoteEnd
+
+-- doubleQuoted will handle regular double-quoted sections, as well
+-- as dialogues with an open double-quote without a close double-quote
+-- in the same paragraph.
+doubleQuoted :: OrgParser (F Inlines)
+doubleQuoted = try $ do
+ doubleQuoteStart
+ contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
+ (withQuoteContext InDoubleQuote $ (doubleQuoteEnd <* updateLastForbiddenCharPos) >> return
+ (fmap B.doubleQuoted . trimInlinesF $ contents))
+ <|> (return $ return (B.str "\8220") <> contents)
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index e5eccb116..678eecc52 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE FlexibleContexts #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.RST
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -29,32 +30,38 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Conversion from reStructuredText to 'Pandoc' document.
-}
module Text.Pandoc.Readers.RST (
- readRST
+ readRST,
+ readRSTWithWarnings
) where
import Text.Pandoc.Definition
import Text.Pandoc.Builder (setMeta, fromList)
import Text.Pandoc.Shared
import Text.Pandoc.Parsing
import Text.Pandoc.Options
-import Control.Monad ( when, liftM, guard, mzero, mplus )
+import Control.Monad ( when, liftM, guard, mzero )
import Data.List ( findIndex, intersperse, intercalate,
- transpose, sort, deleteFirstsBy, isSuffixOf )
+ transpose, sort, deleteFirstsBy, isSuffixOf , nub, union)
import Data.Maybe (fromMaybe)
import qualified Data.Map as M
import Text.Printf ( printf )
-import Control.Applicative ((<$>), (<$), (<*), (*>), (<*>))
+import Control.Applicative ((<$>), (<$), (<*), (*>), (<*>), pure)
import Text.Pandoc.Builder (Inlines, Blocks, trimInlines, (<>))
import qualified Text.Pandoc.Builder as B
import Data.Monoid (mconcat, mempty)
import Data.Sequence (viewr, ViewR(..))
-import Data.Char (toLower, isHexDigit)
+import Data.Char (toLower, isHexDigit, isSpace)
+
+import Text.Pandoc.Error
-- | Parse reStructuredText string and return Pandoc document.
readRST :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readRST opts s = (readWith parseRST) def{ stateOptions = opts } (s ++ "\n\n")
+readRSTWithWarnings :: ReaderOptions -> String -> Either PandocError (Pandoc, [String])
+readRSTWithWarnings opts s = (readWithWarnings parseRST) def{ stateOptions = opts } (s ++ "\n\n")
+
type RSTParser = Parser [Char] ParserState
--
@@ -202,7 +209,7 @@ rawFieldListItem minIndent = try $ do
fieldListItem :: Int -> RSTParser (Inlines, [Blocks])
fieldListItem minIndent = try $ do
(name, raw) <- rawFieldListItem minIndent
- let term = B.str name
+ term <- parseInlineFromString name
contents <- parseFromString parseBlocks raw
optional blanklines
return (term, [contents])
@@ -222,8 +229,7 @@ fieldList = try $ do
lineBlock :: RSTParser Blocks
lineBlock = try $ do
lines' <- lineBlockLines
- lines'' <- mapM (parseFromString
- (trimInlines . mconcat <$> many inline)) lines'
+ lines'' <- mapM parseInlineFromString lines'
return $ B.para (mconcat $ intersperse B.linebreak lines'')
--
@@ -335,6 +341,13 @@ indentedBlock = try $ do
optional blanklines
return $ unlines lns
+quotedBlock :: Parser [Char] st [Char]
+quotedBlock = try $ do
+ quote <- lookAhead $ oneOf "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
+ lns <- many1 $ lookAhead (char quote) >> anyLine
+ optional blanklines
+ return $ unlines lns
+
codeBlockStart :: Parser [Char] st Char
codeBlockStart = string "::" >> blankline >> blankline
@@ -342,7 +355,8 @@ codeBlock :: Parser [Char] st Blocks
codeBlock = try $ codeBlockStart >> codeBlockBody
codeBlockBody :: Parser [Char] st Blocks
-codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$> indentedBlock
+codeBlockBody = try $ B.codeBlock . stripTrailingNewlines <$>
+ (indentedBlock <|> quotedBlock)
lhsCodeBlock :: RSTParser Blocks
lhsCodeBlock = try $ do
@@ -513,7 +527,6 @@ directive = try $ do
-- TODO: line-block, parsed-literal, table, csv-table, list-table
-- date
-- include
--- class
-- title
directive' :: RSTParser Blocks
directive' = do
@@ -535,39 +548,33 @@ directive' = do
"role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields
"container" -> parseFromString parseBlocks body'
"replace" -> B.para <$> -- consumed by substKey
- parseFromString (trimInlines . mconcat <$> many inline)
- (trim top)
+ parseInlineFromString (trim top)
"unicode" -> B.para <$> -- consumed by substKey
- parseFromString (trimInlines . mconcat <$> many inline)
- (trim $ unicodeTransform top)
+ parseInlineFromString (trim $ unicodeTransform top)
"compound" -> parseFromString parseBlocks body'
"pull-quote" -> B.blockQuote <$> parseFromString parseBlocks body'
"epigraph" -> B.blockQuote <$> parseFromString parseBlocks body'
"highlights" -> B.blockQuote <$> parseFromString parseBlocks body'
- "rubric" -> B.para . B.strong <$> parseFromString
- (trimInlines . mconcat <$> many inline) top
+ "rubric" -> B.para . B.strong <$> parseInlineFromString top
_ | label `elem` ["attention","caution","danger","error","hint",
"important","note","tip","warning"] ->
do let tit = B.para $ B.strong $ B.str label
bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
return $ B.blockQuote $ tit <> bod
"admonition" ->
- do tit <- B.para . B.strong <$> parseFromString
- (trimInlines . mconcat <$> many inline) top
+ do tit <- B.para . B.strong <$> parseInlineFromString top
bod <- parseFromString parseBlocks body'
return $ B.blockQuote $ tit <> bod
"sidebar" ->
do let subtit = maybe "" trim $ lookup "subtitle" fields
- tit <- B.para . B.strong <$> parseFromString
- (trimInlines . mconcat <$> many inline)
+ tit <- B.para . B.strong <$> parseInlineFromString
(trim top ++ if null subtit
then ""
else (": " ++ subtit))
bod <- parseFromString parseBlocks body'
return $ B.blockQuote $ tit <> bod
"topic" ->
- do tit <- B.para . B.strong <$> parseFromString
- (trimInlines . mconcat <$> many inline) top
+ do tit <- B.para . B.strong <$> parseInlineFromString top
bod <- parseFromString parseBlocks body'
return $ tit <> bod
"default-role" -> mempty <$ updateState (\s ->
@@ -594,38 +601,69 @@ directive' = do
Just t -> B.link (escapeURI $ trim t) ""
$ B.image src "" alt
Nothing -> B.image src "" alt
- _ -> return mempty
+ "class" -> do
+ let attrs = ("", (splitBy isSpace $ trim top), map (\(k,v) -> (k, trimr v)) fields)
+ -- directive content or the first immediately following element
+ children <- case body of
+ "" -> block
+ _ -> parseFromString parseBlocks body'
+ return $ B.divWith attrs children
+ other -> do
+ pos <- getPosition
+ addWarning (Just pos) $ "ignoring unknown directive: " ++ other
+ return mempty
-- TODO:
-- - Silently ignores illegal fields
--- - Silently drops classes
-- - Only supports :format: fields with a single format for :raw: roles,
-- change Text.Pandoc.Definition.Format to fix
addNewRole :: String -> [(String, String)] -> RSTParser Blocks
addNewRole roleString fields = do
(role, parentRole) <- parseFromString inheritedRole roleString
customRoles <- stateRstCustomRoles <$> getState
- baseRole <- case M.lookup parentRole customRoles of
- Just (base, _, _) -> return base
- Nothing -> return parentRole
-
- let fmt = if baseRole == "raw" then lookup "format" fields else Nothing
- annotate = maybe id addLanguage $
- if baseRole == "code"
+ let (baseRole, baseFmt, baseAttr) =
+ maybe (parentRole, Nothing, nullAttr) id $
+ M.lookup parentRole customRoles
+ fmt = if parentRole == "raw" then lookup "format" fields else baseFmt
+ annotate :: [String] -> [String]
+ annotate = maybe id (:) $
+ if parentRole == "code"
then lookup "language" fields
else Nothing
+ attr = let (ident, classes, keyValues) = baseAttr
+ -- nub in case role name & language class are the same
+ in (ident, nub . (role :) . annotate $ classes, keyValues)
+
+ -- warn about syntax we ignore
+ flip mapM_ fields $ \(key, _) -> case key of
+ "language" -> when (parentRole /= "code") $ addWarning Nothing $
+ "ignoring :language: field because the parent of role :" ++
+ role ++ ": is :" ++ parentRole ++ ": not :code:"
+ "format" -> when (parentRole /= "raw") $ addWarning Nothing $
+ "ignoring :format: field because the parent of role :" ++
+ role ++ ": is :" ++ parentRole ++ ": not :raw:"
+ _ -> addWarning Nothing $ "ignoring unknown field :" ++ key ++
+ ": in definition of role :" ++ role ++ ": in"
+ when (parentRole == "raw" && countKeys "format" > 1) $
+ addWarning Nothing $
+ "ignoring :format: fields after the first in the definition of role :"
+ ++ role ++": in"
+ when (parentRole == "code" && countKeys "language" > 1) $
+ addWarning Nothing $
+ "ignoring :language: fields after the first in the definition of role :"
+ ++ role ++": in"
updateState $ \s -> s {
stateRstCustomRoles =
- M.insert role (baseRole, fmt, (,) parentRole . annotate) customRoles
+ M.insert role (baseRole, fmt, attr) customRoles
}
return $ B.singleton Null
where
- addLanguage lang (ident, classes, keyValues) =
- (ident, "sourceCode" : lang : classes, keyValues)
+ countKeys k = length . filter (== k) . map fst $ fields
inheritedRole =
- (,) <$> roleNameEndingIn (char '(') <*> roleNameEndingIn (char ')')
+ (,) <$> roleName <*> ((char '(' *> roleName <* char ')') <|> pure "span")
+
-- Can contain character codes as decimal numbers or
-- hexadecimal numbers, prefixed by 0x, x, \x, U+, u, or \u
@@ -666,7 +704,7 @@ extractCaption = do
toChunks :: String -> [String]
toChunks = dropWhile null
. map (trim . unlines)
- . splitBy (all (`elem` " \t")) . lines
+ . splitBy (all (`elem` (" \t" :: String))) . lines
codeblock :: Maybe String -> String -> String -> RSTParser Blocks
codeblock numberLines lang body =
@@ -734,7 +772,7 @@ simpleReferenceName' :: Parser [Char] st String
simpleReferenceName' = do
x <- alphaNum
xs <- many $ alphaNum
- <|> (try $ oneOf "-_:+." >> lookAhead alphaNum)
+ <|> (try $ oneOf "-_:+." <* lookAhead alphaNum)
return (x:xs)
simpleReferenceName :: Parser [Char] st Inlines
@@ -917,6 +955,9 @@ inline = choice [ whitespace
, escapedChar
, symbol ] <?> "inline"
+parseInlineFromString :: String -> RSTParser Inlines
+parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline)
+
hyphens :: RSTParser Inlines
hyphens = do
result <- many1 (char '-')
@@ -985,21 +1026,23 @@ renderRole contents fmt role attr = case role of
"RFC" -> return $ rfcLink contents
"pep-reference" -> return $ pepLink contents
"PEP" -> return $ pepLink contents
- "literal" -> return $ B.str contents
+ "literal" -> return $ B.codeWith attr contents
"math" -> return $ B.math contents
"title-reference" -> titleRef contents
"title" -> titleRef contents
"t" -> titleRef contents
- "code" -> return $ B.codeWith attr contents
+ "code" -> return $ B.codeWith (addClass "sourceCode" attr) contents
+ "span" -> return $ B.spanWith attr $ B.str contents
"raw" -> return $ B.rawInline (fromMaybe "" fmt) contents
custom -> do
- customRole <- stateRstCustomRoles <$> getState
- case M.lookup custom customRole of
- Just (_, newFmt, inherit) -> let
- fmtStr = fmt `mplus` newFmt
- (newRole, newAttr) = inherit attr
- in renderRole contents fmtStr newRole newAttr
- Nothing -> return $ B.str contents -- Undefined role
+ customRoles <- stateRstCustomRoles <$> getState
+ case M.lookup custom customRoles of
+ Just (newRole, newFmt, newAttr) ->
+ renderRole contents newFmt newRole newAttr
+ Nothing -> do
+ pos <- getPosition
+ addWarning (Just pos) $ "ignoring unknown role :" ++ custom ++ ": in"
+ return $ B.str contents -- Undefined role
where
titleRef ref = return $ B.str ref -- FIXME: Not a sensible behaviour
rfcLink rfcNo = B.link rfcUrl ("RFC " ++ rfcNo) $ B.str ("RFC " ++ rfcNo)
@@ -1008,11 +1051,14 @@ renderRole contents fmt role attr = case role of
where padNo = replicate (4 - length pepNo) '0' ++ pepNo
pepUrl = "http://www.python.org/dev/peps/pep-" ++ padNo ++ "/"
-roleNameEndingIn :: RSTParser Char -> RSTParser String
-roleNameEndingIn end = many1Till (letter <|> char '-') end
+addClass :: String -> Attr -> Attr
+addClass c (ident, classes, keyValues) = (ident, union classes [c], keyValues)
+
+roleName :: RSTParser String
+roleName = many1 (letter <|> char '-')
roleMarker :: RSTParser String
-roleMarker = char ':' *> roleNameEndingIn (char ':')
+roleMarker = char ':' *> roleName <* char ':'
roleBefore :: RSTParser (String,String)
roleBefore = try $ do
diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs
new file mode 100644
index 000000000..07b414431
--- /dev/null
+++ b/src/Text/Pandoc/Readers/TWiki.hs
@@ -0,0 +1,527 @@
+{-# LANGUAGE RelaxedPolyRec, FlexibleInstances, TypeSynonymInstances, FlexibleContexts #-}
+-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
+{-
+ Copyright (C) 2014 Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Readers.TWiki
+ Copyright : Copyright (C) 2014 Alexander Sulfrian
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
+ Stability : alpha
+ Portability : portable
+
+Conversion of twiki text to 'Pandoc' document.
+-}
+module Text.Pandoc.Readers.TWiki ( readTWiki
+ , readTWikiWithWarnings
+ ) where
+
+import Text.Pandoc.Definition
+import qualified Text.Pandoc.Builder as B
+import Text.Pandoc.Options
+import Text.Pandoc.Parsing hiding (enclosed, macro, nested)
+import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
+import Data.Monoid (Monoid, mconcat, mempty)
+import Control.Applicative ((<$>), (<*), (*>), (<$))
+import Control.Monad
+import Text.Printf (printf)
+import Debug.Trace (trace)
+import Text.Pandoc.XML (fromEntities)
+import Data.Maybe (fromMaybe)
+import Text.HTML.TagSoup
+import Data.Char (isAlphaNum)
+import qualified Data.Foldable as F
+import Text.Pandoc.Error
+
+-- | Read twiki from an input string and return a Pandoc document.
+readTWiki :: ReaderOptions -- ^ Reader options
+ -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Either PandocError Pandoc
+readTWiki opts s =
+ (readWith parseTWiki) def{ stateOptions = opts } (s ++ "\n\n")
+
+readTWikiWithWarnings :: ReaderOptions -- ^ Reader options
+ -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Either PandocError (Pandoc, [String])
+readTWikiWithWarnings opts s =
+ (readWith parseTWikiWithWarnings) def{ stateOptions = opts } (s ++ "\n\n")
+ where parseTWikiWithWarnings = do
+ doc <- parseTWiki
+ warnings <- stateWarnings <$> getState
+ return (doc, warnings)
+
+type TWParser = Parser [Char] ParserState
+
+--
+-- utility functions
+--
+
+tryMsg :: String -> TWParser a -> TWParser a
+tryMsg msg p = try p <?> msg
+
+skip :: TWParser a -> TWParser ()
+skip parser = parser >> return ()
+
+nested :: TWParser a -> TWParser a
+nested p = do
+ nestlevel <- stateMaxNestingLevel <$> getState
+ guard $ nestlevel > 0
+ updateState $ \st -> st{ stateMaxNestingLevel = stateMaxNestingLevel st - 1 }
+ res <- p
+ updateState $ \st -> st{ stateMaxNestingLevel = nestlevel }
+ return res
+
+htmlElement :: String -> TWParser (Attr, String)
+htmlElement tag = tryMsg tag $ do
+ (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
+ content <- manyTill anyChar (endtag <|> endofinput)
+ return (htmlAttrToPandoc attr, trim content)
+ where
+ endtag = skip $ htmlTag (~== TagClose tag)
+ endofinput = lookAhead $ try $ skipMany blankline >> skipSpaces >> eof
+ trim = dropWhile (=='\n') . reverse . dropWhile (=='\n') . reverse
+
+htmlAttrToPandoc :: [Attribute String] -> Attr
+htmlAttrToPandoc attrs = (ident, classes, keyvals)
+ where
+ ident = fromMaybe "" $ lookup "id" attrs
+ classes = maybe [] words $ lookup "class" attrs
+ keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
+
+parseHtmlContentWithAttrs :: String -> TWParser a -> TWParser (Attr, [a])
+parseHtmlContentWithAttrs tag parser = do
+ (attr, content) <- htmlElement tag
+ parsedContent <- try $ parseContent content
+ return (attr, parsedContent)
+ where
+ parseContent = parseFromString $ nested $ manyTill parser endOfContent
+ endOfContent = try $ skipMany blankline >> skipSpaces >> eof
+
+parseHtmlContent :: String -> TWParser a -> TWParser [a]
+parseHtmlContent tag p = parseHtmlContentWithAttrs tag p >>= return . snd
+
+--
+-- main parser
+--
+
+parseTWiki :: TWParser Pandoc
+parseTWiki = do
+ bs <- mconcat <$> many block
+ spaces
+ eof
+ return $ B.doc bs
+
+
+--
+-- block parsers
+--
+
+block :: TWParser B.Blocks
+block = do
+ tr <- getOption readerTrace
+ pos <- getPosition
+ res <- mempty <$ skipMany1 blankline
+ <|> blockElements
+ <|> para
+ skipMany blankline
+ when tr $
+ trace (printf "line %d: %s" (sourceLine pos)
+ (take 60 $ show $ B.toList res)) (return ())
+ return res
+
+blockElements :: TWParser B.Blocks
+blockElements = choice [ separator
+ , header
+ , verbatim
+ , literal
+ , list ""
+ , table
+ , blockQuote
+ , noautolink
+ ]
+
+separator :: TWParser B.Blocks
+separator = tryMsg "separator" $ string "---" >> newline >> return B.horizontalRule
+
+header :: TWParser B.Blocks
+header = tryMsg "header" $ do
+ string "---"
+ level <- many1 (char '+') >>= return . length
+ guard $ level <= 6
+ classes <- option [] $ string "!!" >> return ["unnumbered"]
+ skipSpaces
+ content <- B.trimInlines . mconcat <$> manyTill inline newline
+ attr <- registerHeader ("", classes, []) content
+ return $ B.headerWith attr level $ content
+
+verbatim :: TWParser B.Blocks
+verbatim = (htmlElement "verbatim" <|> htmlElement "pre")
+ >>= return . (uncurry B.codeBlockWith)
+
+literal :: TWParser B.Blocks
+literal = htmlElement "literal" >>= return . rawBlock
+ where
+ format (_, _, kvs) = fromMaybe "html" $ lookup "format" kvs
+ rawBlock (attrs, content) = B.rawBlock (format attrs) content
+
+list :: String -> TWParser B.Blocks
+list prefix = choice [ bulletList prefix
+ , orderedList prefix
+ , definitionList prefix]
+
+definitionList :: String -> TWParser B.Blocks
+definitionList prefix = tryMsg "definitionList" $ do
+ indent <- lookAhead $ string prefix *> (many1 $ string " ") <* string "$ "
+ elements <- many $ parseDefinitionListItem (prefix ++ concat indent)
+ return $ B.definitionList elements
+ where
+ parseDefinitionListItem :: String -> TWParser (B.Inlines, [B.Blocks])
+ parseDefinitionListItem indent = do
+ string (indent ++ "$ ") >> skipSpaces
+ term <- many1Till inline $ string ": "
+ line <- listItemLine indent $ string "$ "
+ return $ (mconcat term, [line])
+
+bulletList :: String -> TWParser B.Blocks
+bulletList prefix = tryMsg "bulletList" $
+ parseList prefix (char '*') (char ' ')
+
+orderedList :: String -> TWParser B.Blocks
+orderedList prefix = tryMsg "orderedList" $
+ parseList prefix (oneOf "1iIaA") (string ". ")
+
+parseList :: Show a => String -> TWParser Char -> TWParser a -> TWParser B.Blocks
+parseList prefix marker delim = do
+ (indent, style) <- lookAhead $ string prefix *> listStyle <* delim
+ blocks <- many $ parseListItem (prefix ++ indent) (char style <* delim)
+ return $ case style of
+ '1' -> B.orderedListWith (1, DefaultStyle, DefaultDelim) blocks
+ 'i' -> B.orderedListWith (1, LowerRoman, DefaultDelim) blocks
+ 'I' -> B.orderedListWith (1, UpperRoman, DefaultDelim) blocks
+ 'a' -> B.orderedListWith (1, LowerAlpha, DefaultDelim) blocks
+ 'A' -> B.orderedListWith (1, UpperAlpha, DefaultDelim) blocks
+ _ -> B.bulletList blocks
+ where
+ listStyle = do
+ indent <- many1 $ string " "
+ style <- marker
+ return (concat indent, style)
+
+parseListItem :: Show a => String -> TWParser a -> TWParser B.Blocks
+parseListItem prefix marker = string prefix >> marker >> listItemLine prefix marker
+
+listItemLine :: Show a => String -> TWParser a -> TWParser B.Blocks
+listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat
+ where
+ lineContent = do
+ content <- anyLine
+ continuation <- optionMaybe listContinuation
+ return $ filterSpaces content ++ "\n" ++ (maybe "" (" " ++) continuation)
+ filterSpaces = reverse . dropWhile (== ' ') . reverse
+ listContinuation = notFollowedBy (string prefix >> marker) >>
+ string " " >> lineContent
+ parseContent = parseFromString $ many1 $ nestedList <|> parseInline
+ parseInline = many1Till inline (lastNewline <|> newlineBeforeNestedList) >>=
+ return . B.plain . mconcat
+ nestedList = list prefix
+ lastNewline = try $ char '\n' <* eof
+ newlineBeforeNestedList = try $ char '\n' <* lookAhead nestedList
+
+table :: TWParser B.Blocks
+table = try $ do
+ tableHead <- optionMaybe $ many1Till tableParseHeader newline >>= return . unzip
+ rows <- many1 tableParseRow
+ return $ buildTable mempty rows $ fromMaybe (align rows, columns rows) tableHead
+ where
+ buildTable caption rows (aligns, heads)
+ = B.table caption aligns heads rows
+ align rows = replicate (columCount rows) (AlignDefault, 0)
+ columns rows = replicate (columCount rows) mempty
+ columCount rows = length $ head rows
+
+tableParseHeader :: TWParser ((Alignment, Double), B.Blocks)
+tableParseHeader = try $ do
+ char '|'
+ leftSpaces <- many spaceChar >>= return . length
+ char '*'
+ content <- tableColumnContent (char '*' >> skipSpaces >> char '|')
+ char '*'
+ rightSpaces <- many spaceChar >>= return . length
+ optional tableEndOfRow
+ return (tableAlign leftSpaces rightSpaces, content)
+ where
+ tableAlign left right
+ | left >= 2 && left == right = (AlignCenter, 0)
+ | left > right = (AlignRight, 0)
+ | otherwise = (AlignLeft, 0)
+
+tableParseRow :: TWParser [B.Blocks]
+tableParseRow = many1Till tableParseColumn newline
+
+tableParseColumn :: TWParser B.Blocks
+tableParseColumn = char '|' *> skipSpaces *>
+ tableColumnContent (skipSpaces >> char '|')
+ <* skipSpaces <* optional tableEndOfRow
+
+tableEndOfRow :: TWParser Char
+tableEndOfRow = lookAhead (try $ char '|' >> char '\n') >> char '|'
+
+tableColumnContent :: Show a => TWParser a -> TWParser B.Blocks
+tableColumnContent end = manyTill content (lookAhead $ try end) >>= return . B.plain . mconcat
+ where
+ content = continuation <|> inline
+ continuation = try $ char '\\' >> newline >> return mempty
+
+blockQuote :: TWParser B.Blocks
+blockQuote = parseHtmlContent "blockquote" block >>= return . B.blockQuote . mconcat
+
+noautolink :: TWParser B.Blocks
+noautolink = do
+ (_, content) <- htmlElement "noautolink"
+ st <- getState
+ setState $ st{ stateAllowLinks = False }
+ blocks <- try $ parseContent content
+ setState $ st{ stateAllowLinks = True }
+ return $ mconcat blocks
+ where
+ parseContent = parseFromString $ many $ block
+
+para :: TWParser B.Blocks
+para = many1Till inline endOfParaElement >>= return . result . mconcat
+ where
+ endOfParaElement = lookAhead $ endOfInput <|> endOfPara <|> newBlockElement
+ endOfInput = try $ skipMany blankline >> skipSpaces >> eof
+ endOfPara = try $ blankline >> skipMany1 blankline
+ newBlockElement = try $ blankline >> skip blockElements
+ result content = if F.all (==Space) content
+ then mempty
+ else B.para $ B.trimInlines content
+
+
+--
+-- inline parsers
+--
+
+inline :: TWParser B.Inlines
+inline = choice [ whitespace
+ , br
+ , macro
+ , strong
+ , strongHtml
+ , strongAndEmph
+ , emph
+ , emphHtml
+ , boldCode
+ , smart
+ , link
+ , htmlComment
+ , code
+ , codeHtml
+ , nop
+ , autoLink
+ , str
+ , symbol
+ ] <?> "inline"
+
+whitespace :: TWParser B.Inlines
+whitespace = (lb <|> regsp) >>= return
+ where lb = try $ skipMany spaceChar >> linebreak >> return B.space
+ regsp = try $ skipMany1 spaceChar >> return B.space
+
+br :: TWParser B.Inlines
+br = try $ string "%BR%" >> return B.linebreak
+
+linebreak :: TWParser B.Inlines
+linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
+ where lastNewline = eof >> return mempty
+ innerNewline = return B.space
+
+between :: (Show b, Monoid c) => TWParser a -> TWParser b -> (TWParser b -> TWParser c) -> TWParser c
+between start end p =
+ mconcat <$> try (start >> notFollowedBy whitespace >> many1Till (p end) end)
+
+enclosed :: (Show a, Monoid b) => TWParser a -> (TWParser a -> TWParser b) -> TWParser b
+enclosed sep p = between sep (try $ sep <* endMarker) p
+ where
+ endMarker = lookAhead $ skip endSpace <|> skip (oneOf ".,!?:)|") <|> eof
+ endSpace = (spaceChar <|> newline) >> return B.space
+
+macro :: TWParser B.Inlines
+macro = macroWithParameters <|> withoutParameters
+ where
+ withoutParameters = enclosed (char '%') (\_ -> macroName) >>= return . emptySpan
+ emptySpan name = buildSpan name [] mempty
+
+macroWithParameters :: TWParser B.Inlines
+macroWithParameters = try $ do
+ char '%'
+ name <- macroName
+ (content, kvs) <- attributes
+ char '%'
+ return $ buildSpan name kvs $ B.str content
+
+buildSpan :: String -> [(String, String)] -> B.Inlines -> B.Inlines
+buildSpan className kvs = B.spanWith attrs
+ where
+ attrs = ("", ["twiki-macro", className] ++ additionalClasses, kvsWithoutClasses)
+ additionalClasses = maybe [] words $ lookup "class" kvs
+ kvsWithoutClasses = [(k,v) | (k,v) <- kvs, k /= "class"]
+
+macroName :: TWParser String
+macroName = do
+ first <- letter
+ rest <- many $ alphaNum <|> char '_'
+ return (first:rest)
+
+attributes :: TWParser (String, [(String, String)])
+attributes = char '{' *> spnl *> many (attribute <* spnl) <* char '}' >>=
+ return . foldr (either mkContent mkKvs) ([], [])
+ where
+ spnl = skipMany (spaceChar <|> newline)
+ mkContent c ([], kvs) = (c, kvs)
+ mkContent c (rest, kvs) = (c ++ " " ++ rest, kvs)
+ mkKvs kv (cont, rest) = (cont, (kv : rest))
+
+attribute :: TWParser (Either String (String, String))
+attribute = withKey <|> withoutKey
+ where
+ withKey = try $ do
+ key <- macroName
+ char '='
+ parseValue False >>= return . (curry Right key)
+ withoutKey = try $ parseValue True >>= return . Left
+ parseValue allowSpaces = (withQuotes <|> withoutQuotes allowSpaces) >>= return . fromEntities
+ withQuotes = between (char '"') (char '"') (\_ -> count 1 $ noneOf ['"'])
+ withoutQuotes allowSpaces
+ | allowSpaces == True = many1 $ noneOf "}"
+ | otherwise = many1 $ noneOf " }"
+
+nestedInlines :: Show a => TWParser a -> TWParser B.Inlines
+nestedInlines end = innerSpace <|> nestedInline
+ where
+ innerSpace = try $ whitespace <* (notFollowedBy end)
+ nestedInline = notFollowedBy whitespace >> nested inline
+
+strong :: TWParser B.Inlines
+strong = try $ enclosed (char '*') nestedInlines >>= return . B.strong
+
+strongHtml :: TWParser B.Inlines
+strongHtml = (parseHtmlContent "strong" inline <|> parseHtmlContent "b" inline)
+ >>= return . B.strong . mconcat
+
+strongAndEmph :: TWParser B.Inlines
+strongAndEmph = try $ enclosed (string "__") nestedInlines >>= return . B.emph . B.strong
+
+emph :: TWParser B.Inlines
+emph = try $ enclosed (char '_') nestedInlines >>= return . B.emph
+
+emphHtml :: TWParser B.Inlines
+emphHtml = (parseHtmlContent "em" inline <|> parseHtmlContent "i" inline)
+ >>= return . B.emph . mconcat
+
+nestedString :: Show a => TWParser a -> TWParser String
+nestedString end = innerSpace <|> (count 1 nonspaceChar)
+ where
+ innerSpace = try $ many1 spaceChar <* notFollowedBy end
+
+boldCode :: TWParser B.Inlines
+boldCode = try $ enclosed (string "==") nestedString >>= return . B.strong . B.code . fromEntities
+
+htmlComment :: TWParser B.Inlines
+htmlComment = htmlTag isCommentTag >> return mempty
+
+code :: TWParser B.Inlines
+code = try $ enclosed (char '=') nestedString >>= return . B.code . fromEntities
+
+codeHtml :: TWParser B.Inlines
+codeHtml = do
+ (attrs, content) <- parseHtmlContentWithAttrs "code" anyChar
+ return $ B.codeWith attrs $ fromEntities content
+
+autoLink :: TWParser B.Inlines
+autoLink = try $ do
+ state <- getState
+ guard $ stateAllowLinks state
+ (text, url) <- parseLink
+ guard $ checkLink (head $ reverse url)
+ return $ makeLink (text, url)
+ where
+ parseLink = notFollowedBy nop >> (uri <|> emailAddress)
+ makeLink (text, url) = B.link url "" $ B.str text
+ checkLink c
+ | c == '/' = True
+ | otherwise = isAlphaNum c
+
+str :: TWParser B.Inlines
+str = (many1 alphaNum <|> count 1 characterReference) >>= return . B.str
+
+nop :: TWParser B.Inlines
+nop = try $ (skip exclamation <|> skip nopTag) >> followContent
+ where
+ exclamation = char '!'
+ nopTag = stringAnyCase "<nop>"
+ followContent = many1 nonspaceChar >>= return . B.str . fromEntities
+
+symbol :: TWParser B.Inlines
+symbol = count 1 nonspaceChar >>= return . B.str
+
+smart :: TWParser B.Inlines
+smart = do
+ getOption readerSmart >>= guard
+ doubleQuoted <|> singleQuoted <|>
+ choice [ apostrophe
+ , dash
+ , ellipses
+ ]
+
+singleQuoted :: TWParser B.Inlines
+singleQuoted = try $ do
+ singleQuoteStart
+ withQuoteContext InSingleQuote $
+ many1Till inline singleQuoteEnd >>=
+ (return . B.singleQuoted . B.trimInlines . mconcat)
+
+doubleQuoted :: TWParser B.Inlines
+doubleQuoted = try $ do
+ doubleQuoteStart
+ contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
+ (withQuoteContext InDoubleQuote $ doubleQuoteEnd >>
+ return (B.doubleQuoted $ B.trimInlines contents))
+ <|> (return $ (B.str "\8220") B.<> contents)
+
+link :: TWParser B.Inlines
+link = try $ do
+ st <- getState
+ guard $ stateAllowLinks st
+ setState $ st{ stateAllowLinks = False }
+ (url, title, content) <- linkText
+ setState $ st{ stateAllowLinks = True }
+ return $ B.link url title content
+
+linkText :: TWParser (String, String, B.Inlines)
+linkText = do
+ string "[["
+ url <- many1Till anyChar (char ']')
+ content <- option [B.str url] linkContent
+ char ']'
+ return (url, "", mconcat content)
+ where
+ linkContent = (char '[') >> many1Till anyChar (char ']') >>= parseLinkContent
+ parseLinkContent = parseFromString $ many1 inline
diff --git a/src/Text/Pandoc/Readers/TeXMath.hs b/src/Text/Pandoc/Readers/TeXMath.hs
index 3fee3051e..e5778b123 100644
--- a/src/Text/Pandoc/Readers/TeXMath.hs
+++ b/src/Text/Pandoc/Readers/TeXMath.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2007-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.TeXMath
- Copyright : Copyright (C) 2007-2014 John MacFarlane
+ Copyright : Copyright (C) 2007-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index ee64e8f2a..ec1da896d 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2014 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
+Copyright (C) 2010-2015 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
and John MacFarlane
This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Textile
- Copyright : Copyright (C) 2010-2014 Paul Rivier and John MacFarlane
+ Copyright : Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Paul Rivier <paul*rivier#demotera*com>
@@ -57,6 +57,7 @@ import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Options
import Text.Pandoc.Parsing
import Text.Pandoc.Readers.HTML ( htmlTag, isBlockTag )
+import Text.Pandoc.Shared (trim)
import Text.Pandoc.Readers.LaTeX ( rawLaTeXInline, rawLaTeXBlock )
import Text.HTML.TagSoup (parseTags, innerText, fromAttrib, Tag(..))
import Text.HTML.TagSoup.Match
@@ -67,11 +68,12 @@ import Text.Printf
import Control.Applicative ((<$>), (*>), (<*), (<$))
import Data.Monoid
import Debug.Trace (trace)
+import Text.Pandoc.Error
-- | Parse a Textile text and return a Pandoc document.
readTextile :: ReaderOptions -- ^ Reader options
-> String -- ^ String to parse (assuming @'\n'@ line endings)
- -> Pandoc
+ -> Either PandocError Pandoc
readTextile opts s =
(readWith parseTextile) def{ stateOptions = opts } (s ++ "\n\n")
@@ -325,33 +327,30 @@ para = B.para . trimInlines . mconcat <$> many1 inline
-- Tables
-- | A table cell spans until a pipe |
-tableCell :: Parser [Char] ParserState Blocks
-tableCell = do
- c <- many1 (noneOf "|\n")
- content <- trimInlines . mconcat <$> parseFromString (many1 inline) c
+tableCell :: Bool -> Parser [Char] ParserState Blocks
+tableCell headerCell = try $ do
+ char '|'
+ when headerCell $ () <$ string "_."
+ notFollowedBy blankline
+ raw <- trim <$>
+ many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline))
+ content <- mconcat <$> parseFromString (many inline) raw
return $ B.plain content
-- | A table row is made of many table cells
tableRow :: Parser [Char] ParserState [Blocks]
-tableRow = try $ ( char '|' *>
- (endBy1 tableCell (optional blankline *> char '|')) <* newline)
-
--- | Many table rows
-tableRows :: Parser [Char] ParserState [[Blocks]]
-tableRows = many1 tableRow
+tableRow = many1 (tableCell False) <* char '|' <* newline
--- | Table headers are made of cells separated by a tag "|_."
-tableHeaders :: Parser [Char] ParserState [Blocks]
-tableHeaders = let separator = (try $ string "|_.") in
- try $ ( separator *> (sepBy1 tableCell separator) <* char '|' <* newline )
+tableHeader :: Parser [Char] ParserState [Blocks]
+tableHeader = many1 (tableCell True) <* char '|' <* newline
-- | A table with an optional header. Current implementation can
-- handle tables with and without header, but will parse cells
-- alignment attributes as content.
table :: Parser [Char] ParserState Blocks
table = try $ do
- headers <- option mempty tableHeaders
- rows <- tableRows
+ headers <- option mempty $ tableHeader
+ rows <- many1 tableRow
blanklines
let nbOfCols = max (length headers) (length $ head rows)
return $ B.table mempty
@@ -607,8 +606,8 @@ langAttr = do
-- | Parses material surrounded by a parser.
surrounded :: Parser [Char] st t -- ^ surrounding parser
- -> Parser [Char] st a -- ^ content parser (to be used repeatedly)
- -> Parser [Char] st [a]
+ -> Parser [Char] st a -- ^ content parser (to be used repeatedly)
+ -> Parser [Char] st [a]
surrounded border =
enclosed (border *> notFollowedBy (oneOf " \t\n\r")) (try border)
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index 6f8c19ac7..304d6d4c5 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -48,11 +48,12 @@ import Data.Monoid (Monoid, mconcat, mempty, mappend)
import Control.Monad (void, guard, when)
import Data.Default
import Control.Monad.Reader (Reader, runReader, asks)
+import Text.Pandoc.Error
import Data.Time.LocalTime (getZonedTime)
import Text.Pandoc.Compat.Directory(getModificationTime)
import Data.Time.Format (formatTime)
-import System.Locale (defaultTimeLocale)
+import Text.Pandoc.Compat.Locale (defaultTimeLocale)
import System.IO.Error (catchIOError)
type T2T = ParserT String ParserState (Reader T2TMeta)
@@ -83,12 +84,12 @@ getT2TMeta inps out = do
return $ T2TMeta curDate curMtime (intercalate ", " inps) out
-- | Read Txt2Tags from an input string returning a Pandoc document
-readTxt2Tags :: T2TMeta -> ReaderOptions -> String -> Pandoc
+readTxt2Tags :: T2TMeta -> ReaderOptions -> String -> Either PandocError Pandoc
readTxt2Tags t opts s = flip runReader t $ readWithM parseT2T (def {stateOptions = opts}) (s ++ "\n\n")
-- | Read Txt2Tags (ignoring all macros) from an input string returning
-- a Pandoc document
-readTxt2TagsNoMacros :: ReaderOptions -> String -> Pandoc
+readTxt2TagsNoMacros :: ReaderOptions -> String -> Either PandocError Pandoc
readTxt2TagsNoMacros = readTxt2Tags def
parseT2T :: T2T Pandoc
@@ -576,4 +577,3 @@ atStart = (sourceColumn <$> getPosition) >>= guard . (== 1)
ignoreSpacesCap :: T2T String -> T2T String
ignoreSpacesCap p = map toLower <$> (spaces *> p <* spaces)
-
diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs
index 5b8f7a75a..a77127286 100644
--- a/src/Text/Pandoc/SelfContained.hs
+++ b/src/Text/Pandoc/SelfContained.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2011-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.SelfContained
- Copyright : Copyright (C) 2011-2014 John MacFarlane
+ Copyright : Copyright (C) 2011-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -40,15 +40,30 @@ import System.FilePath (takeExtension, takeDirectory, (</>))
import Data.Char (toLower, isAscii, isAlphaNum)
import Codec.Compression.GZip as Gzip
import qualified Data.ByteString.Lazy as L
-import Text.Pandoc.Shared (renderTags', err, fetchItem')
+import Text.Pandoc.Shared (renderTags', err, fetchItem', warn, trim)
import Text.Pandoc.MediaBag (MediaBag)
import Text.Pandoc.MIME (MimeType)
-import Text.Pandoc.UTF8 (toString, fromString)
+import Text.Pandoc.UTF8 (toString)
import Text.Pandoc.Options (WriterOptions(..))
+import Data.List (isPrefixOf)
+import Control.Applicative
+import Text.Parsec (runParserT, ParsecT)
+import qualified Text.Parsec as P
+import Control.Monad.Trans (lift)
isOk :: Char -> Bool
isOk c = isAscii c && isAlphaNum c
+makeDataURI :: String -> ByteString -> String
+makeDataURI mime raw =
+ if textual
+ then "data:" ++ mime' ++ "," ++ escapeURIString isOk (toString raw)
+ else "data:" ++ mime' ++ ";base64," ++ toString (encode raw)
+ where textual = "text/" `Data.List.isPrefixOf` mime
+ mime' = if textual && ';' `notElem` mime
+ then mime ++ ";charset=utf-8"
+ else mime -- mime type already has charset
+
convertTag :: MediaBag -> Maybe String -> Tag String -> IO (Tag String)
convertTag media sourceURL t@(TagOpen tagname as)
| tagname `elem`
@@ -58,51 +73,75 @@ convertTag media sourceURL t@(TagOpen tagname as)
where processAttribute (x,y) =
if x == "src" || x == "href" || x == "poster"
then do
- (raw, mime) <- getRaw media sourceURL (fromAttrib "type" t) y
- let enc = "data:" ++ mime ++ ";base64," ++ toString (encode raw)
+ enc <- getDataURI media sourceURL (fromAttrib "type" t) y
return (x, enc)
else return (x,y)
convertTag media sourceURL t@(TagOpen "script" as) =
case fromAttrib "src" t of
[] -> return t
src -> do
- (raw, mime) <- getRaw media sourceURL (fromAttrib "type" t) src
- let enc = "data:" ++ mime ++ "," ++ escapeURIString isOk (toString raw)
+ enc <- getDataURI media sourceURL (fromAttrib "type" t) src
return $ TagOpen "script" (("src",enc) : [(x,y) | (x,y) <- as, x /= "src"])
convertTag media sourceURL t@(TagOpen "link" as) =
case fromAttrib "href" t of
[] -> return t
src -> do
- (raw, mime) <- getRaw media sourceURL (fromAttrib "type" t) src
- let enc = "data:" ++ mime ++ "," ++ escapeURIString isOk (toString raw)
+ enc <- getDataURI media sourceURL (fromAttrib "type" t) src
return $ TagOpen "link" (("href",enc) : [(x,y) | (x,y) <- as, x /= "href"])
convertTag _ _ t = return t
--- NOTE: This is really crude, it doesn't respect CSS comments.
cssURLs :: MediaBag -> Maybe String -> FilePath -> ByteString
-> IO ByteString
-cssURLs media sourceURL d orig =
- case B.breakSubstring "url(" orig of
- (x,y) | B.null y -> return orig
- | otherwise -> do
- let (u,v) = B.breakSubstring ")" $ B.drop 4 y
- let url = toString
- $ case B.take 1 u of
- "\"" -> B.takeWhile (/='"') $ B.drop 1 u
- "'" -> B.takeWhile (/='\'') $ B.drop 1 u
- _ -> u
- let url' = if isURI url
- then url
- else d </> url
- (raw, mime) <- getRaw media sourceURL "" url'
- rest <- cssURLs media sourceURL d v
- let enc = "data:" `B.append` fromString mime `B.append`
- ";base64," `B.append` (encode raw)
- return $ x `B.append` "url(" `B.append` enc `B.append` rest
-
-getRaw :: MediaBag -> Maybe String -> MimeType -> String
- -> IO (ByteString, MimeType)
-getRaw media sourceURL mimetype src = do
+cssURLs media sourceURL d orig = do
+ res <- runParserT (parseCSSUrls media sourceURL d) () "css" orig
+ case res of
+ Left e -> warn ("Could not parse CSS: " ++ show e) >> return orig
+ Right bs -> return bs
+
+parseCSSUrls :: MediaBag -> Maybe String -> FilePath
+ -> ParsecT ByteString () IO ByteString
+parseCSSUrls media sourceURL d = B.concat <$> P.many
+ (pCSSWhite <|> pCSSComment <|> pCSSUrl media sourceURL d <|> pCSSOther)
+
+-- Note: some whitespace in CSS is significant, so we can't collapse it!
+pCSSWhite :: ParsecT ByteString () IO ByteString
+pCSSWhite = B.singleton <$> P.space <* P.spaces
+
+pCSSComment :: ParsecT ByteString () IO ByteString
+pCSSComment = P.try $ do
+ P.string "/*"
+ P.manyTill P.anyChar (P.try (P.string "*/"))
+ return B.empty
+
+pCSSOther :: ParsecT ByteString () IO ByteString
+pCSSOther = do
+ (B.pack <$> P.many1 (P.noneOf "u/ \n\r\t")) <|>
+ (B.singleton <$> P.char 'u') <|>
+ (B.singleton <$> P.char '/')
+
+pCSSUrl :: MediaBag -> Maybe String -> FilePath
+ -> ParsecT ByteString () IO ByteString
+pCSSUrl media sourceURL d = P.try $ do
+ P.string "url("
+ P.spaces
+ quote <- P.option Nothing (Just <$> P.oneOf "\"'")
+ url <- P.manyTill P.anyChar (maybe (P.lookAhead (P.char ')')) P.char quote)
+ P.spaces
+ P.char ')'
+ let fallback = B.pack ("url(" ++ maybe "" (:[]) quote ++ trim url ++
+ maybe "" (:[]) quote ++ ")")
+ case trim url of
+ '#':_ -> return fallback
+ 'd':'a':'t':'a':':':_ -> return fallback
+ u -> do let url' = if isURI u then u else d </> u
+ enc <- lift $ getDataURI media sourceURL "" url'
+ return (B.pack enc)
+
+
+getDataURI :: MediaBag -> Maybe String -> MimeType -> String
+ -> IO String
+getDataURI _ _ _ src@('d':'a':'t':'a':':':_) = return src -- already data: uri
+getDataURI media sourceURL mimetype src = do
let ext = map toLower $ takeExtension src
fetchResult <- fetchItem' media sourceURL src
(raw, respMime) <- case fetchResult of
@@ -128,7 +167,7 @@ getRaw media sourceURL mimetype src = do
result <- if mime == "text/css"
then cssURLs media cssSourceURL (takeDirectory src) raw'
else return raw'
- return (result, mime)
+ return $ makeDataURI mime result
-- | Convert HTML into self-contained HTML, incorporating images,
-- scripts, and CSS using data: URIs.
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index 9aa70e6f2..c09c2f2a0 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -2,7 +2,7 @@
FlexibleContexts, ScopedTypeVariables, PatternGuards,
ViewPatterns #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -21,7 +21,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Shared
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -76,6 +76,8 @@ module Text.Pandoc.Shared (
renderTags',
-- * File handling
inDirectory,
+ getDefaultReferenceDocx,
+ getDefaultReferenceODT,
readDataFile,
readDataFileUTF8,
fetchItem,
@@ -85,6 +87,8 @@ module Text.Pandoc.Shared (
-- * Error handling
err,
warn,
+ mapLeft,
+ hush,
-- * Safe read
safeRead,
-- * Temp directory
@@ -113,10 +117,12 @@ import System.FilePath ( (</>), takeExtension, dropExtension)
import Data.Generics (Typeable, Data)
import qualified Control.Monad.State as S
import qualified Control.Exception as E
-import Control.Monad (msum, unless)
+import Control.Applicative ((<$>))
+import Control.Monad (msum, unless, MonadPlus(..))
import Text.Pandoc.Pretty (charWidth)
-import System.Locale (defaultTimeLocale)
+import Text.Pandoc.Compat.Locale (defaultTimeLocale)
import Data.Time
+import Data.Time.Clock.POSIX
import System.IO (stderr)
import System.IO.Temp
import Text.HTML.TagSoup (renderTagsOptions, RenderOptions(..), Tag(..),
@@ -127,7 +133,8 @@ import Text.Pandoc.Compat.Monoid
import Data.ByteString.Base64 (decodeLenient)
import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
import qualified Data.Text as T (toUpper, pack, unpack)
-import Data.ByteString.Lazy (toChunks)
+import Data.ByteString.Lazy (toChunks, fromChunks)
+import qualified Data.ByteString.Lazy as BL
#ifdef EMBED_DATA_FILES
import Text.Pandoc.Data (dataFiles)
@@ -135,14 +142,20 @@ import Text.Pandoc.Data (dataFiles)
import Paths_pandoc (getDataFileName)
#endif
#ifdef HTTP_CLIENT
-import Network.HTTP.Client (httpLbs, parseUrl, withManager,
+import Network.HTTP.Client (httpLbs, parseUrl,
responseBody, responseHeaders,
Request(port,host))
+#if MIN_VERSION_http_client(0,4,18)
+import Network.HTTP.Client (newManager)
+#else
+import Network.HTTP.Client (withManager)
+#endif
import Network.HTTP.Client.Internal (addProxy)
import Network.HTTP.Client.TLS (tlsManagerSettings)
import System.Environment (getEnv)
import Network.HTTP.Types.Header ( hContentType)
import Network (withSocketsDo)
+import Codec.Archive.Zip
#else
import Network.URI (parseURI)
import Network.HTTP (findHeader, rspBody,
@@ -654,27 +667,32 @@ hierarchicalizeWithIds ((Header level attr@(_,classes,_) title'):xs) = do
sectionContents' <- hierarchicalizeWithIds sectionContents
rest' <- hierarchicalizeWithIds rest
return $ Sec level newnum attr title' sectionContents' : rest'
+hierarchicalizeWithIds ((Div ("",["references"],[])
+ (Header level (ident,classes,kvs) title' : xs)):ys) =
+ hierarchicalizeWithIds ((Header level (ident,("references":classes),kvs)
+ title') : (xs ++ ys))
hierarchicalizeWithIds (x:rest) = do
rest' <- hierarchicalizeWithIds rest
return $ (Blk x) : rest'
headerLtEq :: Int -> Block -> Bool
headerLtEq level (Header l _ _) = l <= level
+headerLtEq level (Div ("",["references"],[]) (Header l _ _ : _)) = l <= level
headerLtEq _ _ = False
-- | Generate a unique identifier from a list of inlines.
-- Second argument is a list of already used identifiers.
uniqueIdent :: [Inline] -> [String] -> String
-uniqueIdent title' usedIdents =
- let baseIdent = case inlineListToIdentifier title' of
+uniqueIdent title' usedIdents
+ = let baseIdent = case inlineListToIdentifier title' of
"" -> "section"
x -> x
- numIdent n = baseIdent ++ "-" ++ show n
- in if baseIdent `elem` usedIdents
- then case find (\x -> numIdent x `notElem` usedIdents) ([1..60000] :: [Int]) of
+ numIdent n = baseIdent ++ "-" ++ show n
+ in if baseIdent `elem` usedIdents
+ then case find (\x -> numIdent x `notElem` usedIdents) ([1..60000] :: [Int]) of
Just x -> numIdent x
Nothing -> baseIdent -- if we have more than 60,000, allow repeats
- else baseIdent
+ else baseIdent
-- | True if block is a Header block.
isHeaderBlock :: Block -> Bool
@@ -740,7 +758,73 @@ inDirectory path action = E.bracket
setCurrentDirectory
(const $ setCurrentDirectory path >> action)
+getDefaultReferenceDocx :: Maybe FilePath -> IO Archive
+getDefaultReferenceDocx datadir = do
+ let paths = ["[Content_Types].xml",
+ "_rels/.rels",
+ "docProps/app.xml",
+ "docProps/core.xml",
+ "word/document.xml",
+ "word/fontTable.xml",
+ "word/footnotes.xml",
+ "word/numbering.xml",
+ "word/settings.xml",
+ "word/webSettings.xml",
+ "word/styles.xml",
+ "word/_rels/document.xml.rels",
+ "word/_rels/footnotes.xml.rels",
+ "word/theme/theme1.xml"]
+ let toLazy = fromChunks . (:[])
+ let pathToEntry path = do epochtime <- (floor . utcTimeToPOSIXSeconds) <$>
+ getCurrentTime
+ contents <- toLazy <$> readDataFile datadir
+ ("docx/" ++ path)
+ return $ toEntry path epochtime contents
+ mbArchive <- case datadir of
+ Nothing -> return Nothing
+ Just d -> do
+ exists <- doesFileExist (d </> "reference.docx")
+ if exists
+ then return (Just (d </> "reference.docx"))
+ else return Nothing
+ case mbArchive of
+ Just arch -> toArchive <$> BL.readFile arch
+ Nothing -> foldr addEntryToArchive emptyArchive <$>
+ mapM pathToEntry paths
+
+getDefaultReferenceODT :: Maybe FilePath -> IO Archive
+getDefaultReferenceODT datadir = do
+ let paths = ["mimetype",
+ "manifest.rdf",
+ "styles.xml",
+ "content.xml",
+ "meta.xml",
+ "settings.xml",
+ "Configurations2/accelerator/current.xml",
+ "Thumbnails/thumbnail.png",
+ "META-INF/manifest.xml"]
+ let pathToEntry path = do epochtime <- floor `fmap` getPOSIXTime
+ contents <- (fromChunks . (:[])) `fmap`
+ readDataFile datadir ("odt/" ++ path)
+ return $ toEntry path epochtime contents
+ mbArchive <- case datadir of
+ Nothing -> return Nothing
+ Just d -> do
+ exists <- doesFileExist (d </> "reference.odt")
+ if exists
+ then return (Just (d </> "reference.odt"))
+ else return Nothing
+ case mbArchive of
+ Just arch -> toArchive <$> BL.readFile arch
+ Nothing -> foldr addEntryToArchive emptyArchive <$>
+ mapM pathToEntry paths
+
+
readDefaultDataFile :: FilePath -> IO BS.ByteString
+readDefaultDataFile "reference.docx" =
+ (BS.concat . toChunks . fromArchive) <$> getDefaultReferenceDocx Nothing
+readDefaultDataFile "reference.odt" =
+ (BS.concat . toChunks . fromArchive) <$> getDefaultReferenceODT Nothing
readDefaultDataFile fname =
#ifdef EMBED_DATA_FILES
case lookup (makeCanonical fname) dataFiles of
@@ -752,14 +836,17 @@ readDefaultDataFile fname =
go (_:as) ".." = as
go as x = x : as
#else
- getDataFileName ("data" </> fname) >>= checkExistence >>= BS.readFile
- where checkExistence fn = do
- exists <- doesFileExist fn
- if exists
- then return fn
- else err 97 ("Could not find data file " ++ fname)
+ getDataFileName fname' >>= checkExistence >>= BS.readFile
+ where fname' = if fname == "README" then fname else "data" </> fname
#endif
+checkExistence :: FilePath -> IO FilePath
+checkExistence fn = do
+ exists <- doesFileExist fn
+ if exists
+ then return fn
+ else err 97 ("Could not find data file " ++ fn)
+
-- | Read file from specified user data directory or, if not found there, from
-- Cabal data directory.
readDataFile :: Maybe FilePath -> FilePath -> IO BS.ByteString
@@ -794,6 +881,7 @@ fetchItem sourceURL s =
fp = unEscapeString $ dropFragmentAndQuery s
mime = case takeExtension fp of
".gz" -> getMimeType $ dropExtension fp
+ ".svgz" -> getMimeType $ dropExtension fp ++ ".svg"
x -> getMimeType x
ensureEscaped x@(_:':':'\\':_) = x -- likely windows path
ensureEscaped x = escapeURIString isAllowedInURI x
@@ -822,7 +910,11 @@ openURL u
Right pr -> case parseUrl pr of
Just r -> addProxy (host r) (port r) req
Nothing -> req
+#if MIN_VERSION_http_client(0,4,18)
+ resp <- newManager tlsManagerSettings >>= httpLbs req'
+#else
resp <- withManager tlsManagerSettings $ httpLbs req'
+#endif
return (BS.concat $ toChunks $ responseBody resp,
UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
#else
@@ -855,6 +947,14 @@ warn msg = do
name <- getProgName
UTF8.hPutStrLn stderr $ name ++ ": " ++ msg
+mapLeft :: (a -> b) -> Either a c -> Either b c
+mapLeft f (Left x) = Left (f x)
+mapLeft _ (Right x) = Right x
+
+hush :: Either a b -> Maybe b
+hush (Left _) = Nothing
+hush (Right x) = Just x
+
-- | Remove intermediate "." and ".." directories from a path.
--
-- > collapseFilePath "./foo" == "foo"
@@ -883,11 +983,11 @@ collapseFilePath = joinPath . reverse . foldl go [] . splitDirectories
-- Safe read
--
-safeRead :: (Monad m, Read a) => String -> m a
+safeRead :: (MonadPlus m, Read a) => String -> m a
safeRead s = case reads s of
(d,x):_
| all isSpace x -> return d
- _ -> fail $ "Could not read `" ++ s ++ "'"
+ _ -> mzero
--
-- Temp directory
diff --git a/src/Text/Pandoc/Slides.hs b/src/Text/Pandoc/Slides.hs
index 2b863c780..878c900f7 100644
--- a/src/Text/Pandoc/Slides.hs
+++ b/src/Text/Pandoc/Slides.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Slides
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Templates.hs b/src/Text/Pandoc/Templates.hs
index 4ae6a6d8a..b3243d752 100644
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, CPP,
OverloadedStrings, GeneralizedNewtypeDeriving #-}
{-
-Copyright (C) 2009-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2009-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Templates
- Copyright : Copyright (C) 2009-2014 John MacFarlane
+ Copyright : Copyright (C) 2009-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -124,11 +124,12 @@ getDefaultTemplate :: (Maybe FilePath) -- ^ User data directory to search first
-> String -- ^ Name of writer
-> IO (Either E.IOException String)
getDefaultTemplate user writer = do
- let format = takeWhile (`notElem` "+-") writer -- strip off extensions
+ let format = takeWhile (`notElem` ("+-" :: String)) writer -- strip off extensions
case format of
"native" -> return $ Right ""
"json" -> return $ Right ""
"docx" -> return $ Right ""
+ "fb2" -> return $ Right ""
"odt" -> getDefaultTemplate user "opendocument"
"markdown_strict" -> getDefaultTemplate user "markdown"
"multimarkdown" -> getDefaultTemplate user "markdown"
@@ -287,7 +288,7 @@ reservedWords :: [Text]
reservedWords = ["else","endif","for","endfor","sep"]
skipEndline :: Parser ()
-skipEndline = P.try $ P.skipMany (P.satisfy (`elem` " \t")) >> P.char '\n' >> return ()
+skipEndline = P.try $ P.skipMany (P.satisfy (`elem` (" \t" :: String))) >> P.char '\n' >> return ()
pConditional :: Parser Template
pConditional = do
diff --git a/src/Text/Pandoc/UTF8.hs b/src/Text/Pandoc/UTF8.hs
index 543f39ab0..de3314a0d 100644
--- a/src/Text/Pandoc/UTF8.hs
+++ b/src/Text/Pandoc/UTF8.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE CPP #-}
{-
-Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.UTF8
- Copyright : Copyright (C) 2010-2014 John MacFarlane
+ Copyright : Copyright (C) 2010-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -93,10 +93,16 @@ dropBOM :: String -> String
dropBOM ('\xFEFF':xs) = xs
dropBOM xs = xs
+filterCRs :: String -> String
+filterCRs ('\r':'\n':xs) = '\n': filterCRs xs
+filterCRs ('\r':xs) = '\n' : filterCRs xs
+filterCRs (x:xs) = x : filterCRs xs
+filterCRs [] = []
+
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toString :: B.ByteString -> String
-toString = filter (/='\r') . dropBOM . T.unpack . T.decodeUtf8
+toString = filterCRs . dropBOM . T.unpack . T.decodeUtf8
fromString :: String -> B.ByteString
fromString = T.encodeUtf8 . T.pack
@@ -104,7 +110,7 @@ fromString = T.encodeUtf8 . T.pack
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toStringLazy :: BL.ByteString -> String
-toStringLazy = filter (/='\r') . dropBOM . TL.unpack . TL.decodeUtf8
+toStringLazy = filterCRs . dropBOM . TL.unpack . TL.decodeUtf8
fromStringLazy :: String -> BL.ByteString
fromStringLazy = TL.encodeUtf8 . TL.pack
diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs
index eebfe09d2..463be044c 100644
--- a/src/Text/Pandoc/UUID.hs
+++ b/src/Text/Pandoc/UUID.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.UUID
- Copyright : Copyright (C) 2010-2014 John MacFarlane
+ Copyright : Copyright (C) 2010-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index e5b8c5167..bac28e54f 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.AsciiDoc
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -126,7 +126,7 @@ blockToAsciiDoc :: WriterOptions -- ^ Options
blockToAsciiDoc _ Null = return empty
blockToAsciiDoc opts (Plain inlines) = do
contents <- inlineListToAsciiDoc opts inlines
- return $ contents <> cr
+ return $ contents <> blankline
blockToAsciiDoc opts (Para [Image alt (src,'f':'i':'g':':':tit)]) = do
blockToAsciiDoc opts (Para [Image alt (src,tit)])
blockToAsciiDoc opts (Para inlines) = do
@@ -272,7 +272,7 @@ bulletListItemToAsciiDoc opts blocks = do
contents <- foldM addBlock empty blocks
modify $ \s -> s{ bulletListLevel = lev }
let marker = text (replicate lev '*')
- return $ marker <> space <> contents <> cr
+ return $ marker <> text " " <> contents <> cr
-- | Convert ordered list item (a list of blocks) to asciidoc.
orderedListItemToAsciiDoc :: WriterOptions -- ^ options
@@ -292,7 +292,7 @@ orderedListItemToAsciiDoc opts marker blocks = do
modify $ \s -> s{ orderedListLevel = lev + 1 }
contents <- foldM addBlock empty blocks
modify $ \s -> s{ orderedListLevel = lev }
- return $ text marker <> space <> contents <> cr
+ return $ text marker <> text " " <> contents <> cr
-- | Convert definition list item (label, list of blocks) to asciidoc.
definitionListItemToAsciiDoc :: WriterOptions
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
new file mode 100644
index 000000000..fee36d454
--- /dev/null
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -0,0 +1,178 @@
+{-
+Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+-}
+
+{- |
+ Module : Text.Pandoc.Writers.CommonMark
+ Copyright : Copyright (C) 2015 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+
+Conversion of 'Pandoc' documents to CommonMark.
+
+CommonMark: <http://commonmark.org>
+-}
+module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
+
+import Text.Pandoc.Writers.HTML (writeHtmlString)
+import Text.Pandoc.Definition
+import Text.Pandoc.Shared (isTightList)
+import Text.Pandoc.Templates (renderTemplate')
+import Text.Pandoc.Writers.Shared
+import Text.Pandoc.Options
+import CMark
+import qualified Data.Text as T
+import Control.Monad.Identity (runIdentity, Identity)
+import Control.Monad.State (runState, State, modify, get)
+import Text.Pandoc.Walk (walkM)
+
+-- | Convert Pandoc to CommonMark.
+writeCommonMark :: WriterOptions -> Pandoc -> String
+writeCommonMark opts (Pandoc meta blocks) = rendered
+ where main = runIdentity $ blocksToCommonMark opts (blocks' ++ notes')
+ (blocks', notes) = runState (walkM processNotes blocks) []
+ notes' = if null notes
+ then []
+ else [OrderedList (1, Decimal, Period) $ reverse notes]
+ metadata = runIdentity $ metaToJSON opts
+ (blocksToCommonMark opts)
+ (inlinesToCommonMark opts)
+ meta
+ context = defField "body" main $ metadata
+ rendered = if writerStandalone opts
+ then renderTemplate' (writerTemplate opts) context
+ else main
+
+processNotes :: Inline -> State [[Block]] Inline
+processNotes (Note bs) = do
+ modify (bs :)
+ notes <- get
+ return $ Str $ "[" ++ show (length notes) ++ "]"
+processNotes x = return x
+
+node :: NodeType -> [Node] -> Node
+node = Node Nothing
+
+blocksToCommonMark :: WriterOptions -> [Block] -> Identity String
+blocksToCommonMark opts bs = return $
+ T.unpack $ nodeToCommonmark cmarkOpts colwidth
+ $ node DOCUMENT (blocksToNodes bs)
+ where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
+ colwidth = if writerWrapText opts
+ then Just $ writerColumns opts
+ else Nothing
+
+inlinesToCommonMark :: WriterOptions -> [Inline] -> Identity String
+inlinesToCommonMark opts ils = return $
+ T.unpack $ nodeToCommonmark cmarkOpts colwidth
+ $ node PARAGRAPH (inlinesToNodes ils)
+ where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
+ colwidth = if writerWrapText opts
+ then Just $ writerColumns opts
+ else Nothing
+
+blocksToNodes :: [Block] -> [Node]
+blocksToNodes = foldr blockToNodes []
+
+blockToNodes :: Block -> [Node] -> [Node]
+blockToNodes (Plain xs) = (node PARAGRAPH (inlinesToNodes xs) :)
+blockToNodes (Para xs) = (node PARAGRAPH (inlinesToNodes xs) :)
+blockToNodes (CodeBlock (_,classes,_) xs) =
+ (node (CODE_BLOCK (T.pack (unwords classes)) (T.pack xs)) [] :)
+blockToNodes (RawBlock fmt xs)
+ | fmt == Format "html" = (node (HTML (T.pack xs)) [] :)
+ | otherwise = id
+blockToNodes (BlockQuote bs) =
+ (node BLOCK_QUOTE (blocksToNodes bs) :)
+blockToNodes (BulletList items) =
+ (node (LIST ListAttributes{
+ listType = BULLET_LIST,
+ listDelim = PERIOD_DELIM,
+ listTight = isTightList items,
+ listStart = 1 }) (map (node ITEM . blocksToNodes) items) :)
+blockToNodes (OrderedList (start, _sty, delim) items) =
+ (node (LIST ListAttributes{
+ listType = ORDERED_LIST,
+ listDelim = case delim of
+ OneParen -> PAREN_DELIM
+ TwoParens -> PAREN_DELIM
+ _ -> PERIOD_DELIM,
+ listTight = isTightList items,
+ listStart = start }) (map (node ITEM . blocksToNodes) items) :)
+blockToNodes HorizontalRule = (node HRULE [] :)
+blockToNodes (Header lev _ ils) = (node (HEADER lev) (inlinesToNodes ils) :)
+blockToNodes (Div _ bs) = (blocksToNodes bs ++)
+blockToNodes (DefinitionList items) = blockToNodes (BulletList items')
+ where items' = map dlToBullet items
+ dlToBullet (term, ((Para xs : ys) : zs)) =
+ Para (term ++ [LineBreak] ++ xs) : ys ++ concat zs
+ dlToBullet (term, ((Plain xs : ys) : zs)) =
+ Plain (term ++ [LineBreak] ++ xs) : ys ++ concat zs
+ dlToBullet (term, xs) =
+ Para term : concat xs
+blockToNodes t@(Table _ _ _ _ _) =
+ (node (HTML (T.pack $! writeHtmlString def $! Pandoc nullMeta [t])) [] :)
+blockToNodes Null = id
+
+inlinesToNodes :: [Inline] -> [Node]
+inlinesToNodes = foldr inlineToNodes []
+
+inlineToNodes :: Inline -> [Node] -> [Node]
+inlineToNodes (Str s) = (node (TEXT (T.pack s)) [] :)
+inlineToNodes Space = (node (TEXT (T.pack " ")) [] :)
+inlineToNodes LineBreak = (node LINEBREAK [] :)
+inlineToNodes (Emph xs) = (node EMPH (inlinesToNodes xs) :)
+inlineToNodes (Strong xs) = (node STRONG (inlinesToNodes xs) :)
+inlineToNodes (Strikeout xs) =
+ ((node (INLINE_HTML (T.pack "<s>")) [] : inlinesToNodes xs ++
+ [node (INLINE_HTML (T.pack "</s>")) []]) ++ )
+inlineToNodes (Superscript xs) =
+ ((node (INLINE_HTML (T.pack "<sup>")) [] : inlinesToNodes xs ++
+ [node (INLINE_HTML (T.pack "</sup>")) []]) ++ )
+inlineToNodes (Subscript xs) =
+ ((node (INLINE_HTML (T.pack "<sub>")) [] : inlinesToNodes xs ++
+ [node (INLINE_HTML (T.pack "</sub>")) []]) ++ )
+inlineToNodes (SmallCaps xs) =
+ ((node (INLINE_HTML (T.pack "<span style=\"font-variant:small-caps;\">")) []
+ : inlinesToNodes xs ++
+ [node (INLINE_HTML (T.pack "</span>")) []]) ++ )
+inlineToNodes (Link ils (url,tit)) =
+ (node (LINK (T.pack url) (T.pack tit)) (inlinesToNodes ils) :)
+inlineToNodes (Image ils (url,tit)) =
+ (node (IMAGE (T.pack url) (T.pack tit)) (inlinesToNodes ils) :)
+inlineToNodes (RawInline fmt xs)
+ | fmt == Format "html" = (node (INLINE_HTML (T.pack xs)) [] :)
+ | otherwise = id
+inlineToNodes (Quoted qt ils) =
+ ((node (TEXT start) [] : inlinesToNodes ils ++ [node (TEXT end) []]) ++)
+ where (start, end) = case qt of
+ SingleQuote -> (T.pack "‘", T.pack "’")
+ DoubleQuote -> (T.pack "“", T.pack "”")
+inlineToNodes (Code _ str) = (node (CODE (T.pack str)) [] :)
+inlineToNodes (Math mt str) =
+ case mt of
+ InlineMath ->
+ (node (INLINE_HTML (T.pack ("\\(" ++ str ++ "\\)"))) [] :)
+ DisplayMath ->
+ (node (INLINE_HTML (T.pack ("\\[" ++ str ++ "\\]"))) [] :)
+inlineToNodes (Span _ ils) = (inlinesToNodes ils ++)
+inlineToNodes (Cite _ ils) = (inlinesToNodes ils ++)
+inlineToNodes (Note _) = id -- should not occur
+-- we remove Note elements in preprocessing
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index ebdc4a3d3..1f8bbcdba 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2007-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.ConTeXt
- Copyright : Copyright (C) 2007-2014 John MacFarlane
+ Copyright : Copyright (C) 2007-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -119,7 +119,7 @@ stringToConTeXt opts = concatMap (escapeCharForConTeXt opts)
toLabel :: String -> String
toLabel z = concatMap go z
where go x
- | elem x "\\#[]\",{}%()|=" = "ux" ++ printf "%x" (ord x)
+ | elem x ("\\#[]\",{}%()|=" :: String) = "ux" ++ printf "%x" (ord x)
| otherwise = [x]
-- | Convert Elements to ConTeXt
@@ -151,7 +151,13 @@ blockToConTeXt (CodeBlock _ str) =
-- blankline because \stoptyping can't have anything after it, inc. '}'
blockToConTeXt (RawBlock "context" str) = return $ text str <> blankline
blockToConTeXt (RawBlock _ _ ) = return empty
-blockToConTeXt (Div _ bs) = blockListToConTeXt bs
+blockToConTeXt (Div (ident,_,_) bs) = do
+ contents <- blockListToConTeXt bs
+ if null ident
+ then return contents
+ else return $
+ ("\\reference" <> brackets (text $ toLabel ident) <> braces empty <>
+ "%") $$ contents
blockToConTeXt (BulletList lst) = do
contents <- mapM listItemToConTeXt lst
return $ ("\\startitemize" <> if isTightList lst
@@ -296,13 +302,8 @@ inlineToConTeXt (Link txt (('#' : ref), _)) = do
opts <- gets stOptions
contents <- inlineListToConTeXt txt
let ref' = toLabel $ stringToConTeXt opts ref
- return $ text "\\in"
- <> braces (if writerNumberSections opts
- then contents <+> text "(\\S"
- else contents) -- prefix
- <> braces (if writerNumberSections opts
- then text ")"
- else empty) -- suffix
+ return $ text "\\goto"
+ <> braces contents
<> brackets (text ref')
inlineToConTeXt (Link txt (src, _)) = do
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index 914d61850..3a9c1954a 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -1,7 +1,11 @@
-{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverloadedStrings,
- ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
-{- Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+{-# LANGUAGE FlexibleInstances, OverloadedStrings,
+ ScopedTypeVariables, DeriveDataTypeable, CPP #-}
+#if MIN_VERSION_base(4,8,0)
+#else
+{-# LANGUAGE OverlappingInstances #-}
+#endif
+{- Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +24,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Custom
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,40 +39,41 @@ import Text.Pandoc.Definition
import Text.Pandoc.Options
import Data.List ( intersperse )
import Data.Char ( toLower )
+import Data.Typeable
import Scripting.Lua (LuaState, StackValue, callfunc)
import Text.Pandoc.Writers.Shared
import qualified Scripting.Lua as Lua
-import Text.Pandoc.UTF8 (fromString, toString)
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Char8 as C8
+import qualified Text.Pandoc.UTF8 as UTF8
import Data.Monoid
+import Control.Monad (when)
+import Control.Exception
import qualified Data.Map as M
import Text.Pandoc.Templates
+import GHC.IO.Encoding (getForeignEncoding,setForeignEncoding, utf8)
-attrToMap :: Attr -> M.Map ByteString ByteString
+attrToMap :: Attr -> M.Map String String
attrToMap (id',classes,keyvals) = M.fromList
- $ ("id", fromString id')
- : ("class", fromString $ unwords classes)
- : map (\(x,y) -> (fromString x, fromString y)) keyvals
-
-getList :: StackValue a => LuaState -> Int -> IO [a]
-getList lua i' = do
- continue <- Lua.next lua i'
- if continue
- then do
- next <- Lua.peek lua (-1)
- Lua.pop lua 1
- x <- maybe (fail "peek returned Nothing") return next
- rest <- getList lua i'
- return (x : rest)
- else return []
-
-instance StackValue ByteString where
- push l x = Lua.push l $ C8.unpack x
- peek l n = (fmap . fmap) C8.pack (Lua.peek l n)
- valuetype _ = Lua.TSTRING
-
+ $ ("id", id')
+ : ("class", unwords classes)
+ : keyvals
+
+#if MIN_VERSION_hslua(0,4,0)
+#if MIN_VERSION_base(4,8,0)
+instance {-# OVERLAPS #-} StackValue [Char] where
+#else
+instance StackValue [Char] where
+#endif
+ push lua cs = Lua.push lua (UTF8.fromString cs)
+ peek lua i = do
+ res <- Lua.peek lua i
+ return $ UTF8.toString `fmap` res
+ valuetype _ = Lua.TSTRING
+#else
+#if MIN_VERSION_base(4,8,0)
+instance {-# OVERLAPS #-} StackValue a => StackValue [a] where
+#else
instance StackValue a => StackValue [a] where
+#endif
push lua xs = do
Lua.createtable lua (length xs + 1) 0
let addValue (i, x) = Lua.push lua x >> Lua.rawseti lua (-2) i
@@ -82,6 +87,19 @@ instance StackValue a => StackValue [a] where
return (Just lst)
valuetype _ = Lua.TTABLE
+getList :: StackValue a => LuaState -> Int -> IO [a]
+getList lua i' = do
+ continue <- Lua.next lua i'
+ if continue
+ then do
+ next <- Lua.peek lua (-1)
+ Lua.pop lua 1
+ x <- maybe (fail "peek returned Nothing") return next
+ rest <- getList lua i'
+ return (x : rest)
+ else return []
+#endif
+
instance StackValue Format where
push lua (Format f) = Lua.push lua (map toLower f)
peek l n = fmap Format `fmap` Lua.peek l n
@@ -106,13 +124,21 @@ instance (StackValue a, StackValue b) => StackValue (a,b) where
peek _ _ = undefined -- not needed for our purposes
valuetype _ = Lua.TTABLE
+#if MIN_VERSION_base(4,8,0)
+instance {-# OVERLAPS #-} StackValue [Inline] where
+#else
instance StackValue [Inline] where
- push l ils = Lua.push l . C8.unpack =<< inlineListToCustom l ils
+#endif
+ push l ils = Lua.push l =<< inlineListToCustom l ils
peek _ _ = undefined
valuetype _ = Lua.TSTRING
+#if MIN_VERSION_base(4,8,0)
+instance {-# OVERLAPS #-} StackValue [Block] where
+#else
instance StackValue [Block] where
- push l ils = Lua.push l . C8.unpack =<< blockListToCustom l ils
+#endif
+ push l ils = Lua.push l =<< blockListToCustom l ils
peek _ _ = undefined
valuetype _ = Lua.TSTRING
@@ -134,7 +160,7 @@ instance StackValue MetaValue where
instance StackValue Citation where
push lua cit = do
Lua.createtable lua 6 0
- let addValue ((k :: String), v) = Lua.push lua k >> Lua.push lua v >>
+ let addValue (k :: String, v) = Lua.push lua k >> Lua.push lua v >>
Lua.rawset lua (-3)
addValue ("citationId", citationId cit)
addValue ("citationPrefix", citationPrefix cit)
@@ -145,29 +171,45 @@ instance StackValue Citation where
peek = undefined
valuetype _ = Lua.TTABLE
+data PandocLuaException = PandocLuaException String
+ deriving (Show, Typeable)
+
+instance Exception PandocLuaException
+
-- | Convert Pandoc to custom markup.
writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
writeCustom luaFile opts doc@(Pandoc meta _) = do
- luaScript <- C8.unpack `fmap` C8.readFile luaFile
+ luaScript <- UTF8.readFile luaFile
+ enc <- getForeignEncoding
+ setForeignEncoding utf8
lua <- Lua.newstate
Lua.openlibs lua
- Lua.loadstring lua luaScript "custom"
+ status <- Lua.loadstring lua luaScript luaFile
+ -- check for error in lua script (later we'll change the return type
+ -- to handle this more gracefully):
+ when (status /= 0) $
+#if MIN_VERSION_hslua(0,4,0)
+ Lua.tostring lua 1 >>= throw . PandocLuaException . UTF8.toString
+#else
+ Lua.tostring lua 1 >>= throw . PandocLuaException
+#endif
Lua.call lua 0 0
-- TODO - call hierarchicalize, so we have that info
rendered <- docToCustom lua opts doc
context <- metaToJSON opts
- (fmap toString . blockListToCustom lua)
- (fmap toString . inlineListToCustom lua)
+ (blockListToCustom lua)
+ (inlineListToCustom lua)
meta
Lua.close lua
- let body = toString rendered
+ setForeignEncoding enc
+ let body = rendered
if writerStandalone opts
then do
let context' = setField "body" body context
return $ renderTemplate' (writerTemplate opts) context'
else return body
-docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO ByteString
+docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO String
docToCustom lua opts (Pandoc (Meta metamap) blocks) = do
body <- blockListToCustom lua blocks
callfunc lua "Doc" body metamap (writerVariables opts)
@@ -175,7 +217,7 @@ docToCustom lua opts (Pandoc (Meta metamap) blocks) = do
-- | Convert Pandoc block element to Custom.
blockToCustom :: LuaState -- ^ Lua state
-> Block -- ^ Block element
- -> IO ByteString
+ -> IO String
blockToCustom _ Null = return ""
@@ -187,7 +229,7 @@ blockToCustom lua (Para [Image txt (src,tit)]) =
blockToCustom lua (Para inlines) = callfunc lua "Para" inlines
blockToCustom lua (RawBlock format str) =
- callfunc lua "RawBlock" format (fromString str)
+ callfunc lua "RawBlock" format str
blockToCustom lua HorizontalRule = callfunc lua "HorizontalRule"
@@ -195,7 +237,7 @@ blockToCustom lua (Header level attr inlines) =
callfunc lua "Header" level inlines (attrToMap attr)
blockToCustom lua (CodeBlock attr str) =
- callfunc lua "CodeBlock" (fromString str) (attrToMap attr)
+ callfunc lua "CodeBlock" str (attrToMap attr)
blockToCustom lua (BlockQuote blocks) = callfunc lua "BlockQuote" blocks
@@ -216,22 +258,22 @@ blockToCustom lua (Div attr items) =
-- | Convert list of Pandoc block elements to Custom.
blockListToCustom :: LuaState -- ^ Options
-> [Block] -- ^ List of block elements
- -> IO ByteString
+ -> IO String
blockListToCustom lua xs = do
blocksep <- callfunc lua "Blocksep"
bs <- mapM (blockToCustom lua) xs
return $ mconcat $ intersperse blocksep bs
-- | Convert list of Pandoc inline elements to Custom.
-inlineListToCustom :: LuaState -> [Inline] -> IO ByteString
+inlineListToCustom :: LuaState -> [Inline] -> IO String
inlineListToCustom lua lst = do
xs <- mapM (inlineToCustom lua) lst
- return $ C8.concat xs
+ return $ concat xs
-- | Convert Pandoc inline element to Custom.
-inlineToCustom :: LuaState -> Inline -> IO ByteString
+inlineToCustom :: LuaState -> Inline -> IO String
-inlineToCustom lua (Str str) = callfunc lua "Str" $ fromString str
+inlineToCustom lua (Str str) = callfunc lua "Str" str
inlineToCustom lua Space = callfunc lua "Space"
@@ -254,24 +296,24 @@ inlineToCustom lua (Quoted DoubleQuote lst) = callfunc lua "DoubleQuoted" lst
inlineToCustom lua (Cite cs lst) = callfunc lua "Cite" lst cs
inlineToCustom lua (Code attr str) =
- callfunc lua "Code" (fromString str) (attrToMap attr)
+ callfunc lua "Code" str (attrToMap attr)
inlineToCustom lua (Math DisplayMath str) =
- callfunc lua "DisplayMath" (fromString str)
+ callfunc lua "DisplayMath" str
inlineToCustom lua (Math InlineMath str) =
- callfunc lua "InlineMath" (fromString str)
+ callfunc lua "InlineMath" str
inlineToCustom lua (RawInline format str) =
- callfunc lua "RawInline" format (fromString str)
+ callfunc lua "RawInline" format str
inlineToCustom lua (LineBreak) = callfunc lua "LineBreak"
inlineToCustom lua (Link txt (src,tit)) =
- callfunc lua "Link" txt (fromString src) (fromString tit)
+ callfunc lua "Link" txt src tit
inlineToCustom lua (Image alt (src,tit)) =
- callfunc lua "Image" alt (fromString src) (fromString tit)
+ callfunc lua "Image" alt src tit
inlineToCustom lua (Note contents) = callfunc lua "Note" contents
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index b10317506..f3b99e141 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings, PatternGuards #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docbook
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -114,7 +114,8 @@ elementToDocbook opts lvl (Sec _ _num (id',_,_) title elements) =
n | n == 0 -> "chapter"
| n >= 1 && n <= 5 -> "sect" ++ show n
| otherwise -> "simplesect"
- in inTags True tag [("id", writerIdentifierPrefix opts ++ id')] $
+ in inTags True tag [("id", writerIdentifierPrefix opts ++ id') |
+ not (null id')] $
inTagsSimple "title" (inlinesToDocbook opts title) $$
vcat (map (elementToDocbook opts (lvl + 1)) elements')
@@ -153,6 +154,14 @@ listItemToDocbook opts item =
-- | Convert a Pandoc block element to Docbook.
blockToDocbook :: WriterOptions -> Block -> Doc
blockToDocbook _ Null = empty
+-- Add ids to paragraphs in divs with ids - this is needed for
+-- pandoc-citeproc to get link anchors in bibliographies:
+blockToDocbook opts (Div (ident,_,_) [Para lst]) =
+ let attribs = [("id", ident) | not (null ident)] in
+ if hasLineBreaks lst
+ then flush $ nowrap $ inTags False "literallayout" attribs
+ $ inlinesToDocbook opts lst
+ else inTags True "para" attribs $ inlinesToDocbook opts lst
blockToDocbook opts (Div _ bs) = blocksToDocbook opts $ map plainToPara bs
blockToDocbook _ (Header _ _ _) = empty -- should not occur after hierarchicalize
blockToDocbook opts (Plain lst) = inlinesToDocbook opts lst
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index 5320a2816..da4c78cef 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -1,6 +1,6 @@
-{-# LANGUAGE ScopedTypeVariables, PatternGuards #-}
+{-# LANGUAGE ScopedTypeVariables, PatternGuards, ViewPatterns #-}
{-
-Copyright (C) 2012-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docx
- Copyright : Copyright (C) 2012-2014 John MacFarlane
+ Copyright : Copyright (C) 2012-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -41,7 +41,7 @@ import Data.Time.Clock.POSIX
import Data.Time.Clock
import Data.Time.Format
import System.Environment
-import System.Locale
+import Text.Pandoc.Compat.Locale (defaultTimeLocale)
import Text.Pandoc.Definition
import Text.Pandoc.Generic
import Text.Pandoc.ImageSize
@@ -54,6 +54,8 @@ import Text.Pandoc.Walk
import Text.Highlighting.Kate.Types ()
import Text.XML.Light as XML
import Text.TeXMath
+import Text.Pandoc.Readers.Docx.StyleMap
+import Text.Pandoc.Readers.Docx.Util (elemName)
import Control.Monad.State
import Text.Highlighting.Kate
import Data.Unique (hashUnique, newUnique)
@@ -62,8 +64,9 @@ import Text.Printf (printf)
import qualified Control.Exception as E
import Text.Pandoc.MIME (MimeType, getMimeType, getMimeTypeDef,
extensionFromMimeType)
-import Control.Applicative ((<$>), (<|>))
-import Data.Maybe (fromMaybe, mapMaybe)
+import Control.Applicative ((<$>), (<|>), (<*>))
+import Data.Maybe (fromMaybe, mapMaybe, maybeToList)
+import Data.Char (ord)
data ListMarker = NoMarker
| BulletMarker
@@ -104,13 +107,17 @@ data WriterState = WriterState{
, stInDel :: Bool
, stChangesAuthor :: String
, stChangesDate :: String
+ , stPrintWidth :: Integer
+ , stStyleMaps :: StyleMaps
+ , stFirstPara :: Bool
+ , stTocTitle :: [Inline]
}
defaultWriterState :: WriterState
defaultWriterState = WriterState{
stTextProperties = []
, stParaProperties = []
- , stFootnotes = []
+ , stFootnotes = defaultFootnotes
, stSectionIds = []
, stExternalLinks = M.empty
, stImages = M.empty
@@ -122,6 +129,10 @@ defaultWriterState = WriterState{
, stInDel = False
, stChangesAuthor = "unknown"
, stChangesDate = "1969-12-31T19:00:00Z"
+ , stPrintWidth = 1
+ , stStyleMaps = defaultStyleMaps
+ , stFirstPara = False
+ , stTocTitle = normalizeInlines [Str "Table of Contents"]
}
type WS a = StateT WriterState IO a
@@ -168,24 +179,80 @@ renumId f renumMap e
renumIds :: (QName -> Bool) -> (M.Map String String) -> [Element] -> [Element]
renumIds f renumMap = map (renumId f renumMap)
+-- | Certain characters are invalid in XML even if escaped.
+-- See #1992
+stripInvalidChars :: Pandoc -> Pandoc
+stripInvalidChars = bottomUp (filter isValidChar)
+
+-- | See XML reference
+isValidChar :: Char -> Bool
+isValidChar (ord -> c)
+ | c == 0x9 = True
+ | c == 0xA = True
+ | c == 0xD = True
+ | 0x20 <= c && c <= 0xD7FF = True
+ | 0xE000 <= c && c <= 0xFFFD = True
+ | 0x10000 <= c && c <= 0x10FFFF = True
+ | otherwise = False
+
+metaValueToInlines :: MetaValue -> [Inline]
+metaValueToInlines (MetaString s) = normalizeInlines [Str s]
+metaValueToInlines (MetaInlines ils) = ils
+metaValueToInlines (MetaBlocks bs) = query return bs
+metaValueToInlines (MetaBool b) = [Str $ show b]
+metaValueToInlines _ = []
+
-- | Produce an Docx file from a Pandoc document.
writeDocx :: WriterOptions -- ^ Writer options
-> Pandoc -- ^ Document to convert
-> IO BL.ByteString
writeDocx opts doc@(Pandoc meta _) = do
let datadir = writerUserDataDir opts
- let doc' = walk fixDisplayMath doc
+ let doc' = stripInvalidChars . walk fixDisplayMath $ doc
username <- lookup "USERNAME" <$> getEnvironment
utctime <- getCurrentTime
- refArchive <- liftM (toArchive . toLazy) $
- case writerReferenceDocx opts of
- Just f -> B.readFile f
- Nothing -> readDataFile datadir "reference.docx"
- distArchive <- liftM (toArchive . toLazy) $ readDataFile Nothing "reference.docx"
+ distArchive <- getDefaultReferenceDocx Nothing
+ refArchive <- case writerReferenceDocx opts of
+ Just f -> liftM (toArchive . toLazy) $ B.readFile f
+ Nothing -> getDefaultReferenceDocx datadir
+
+ parsedDoc <- parseXml refArchive distArchive "word/document.xml"
+ let wname f qn = qPrefix qn == Just "w" && f (qName qn)
+ let mbsectpr = filterElementName (wname (=="sectPr")) parsedDoc
+
+ -- Gets the template size
+ let mbpgsz = mbsectpr >>= (filterElementName (wname (=="pgSz")))
+ let mbAttrSzWidth = (elAttribs <$> mbpgsz) >>= (lookupAttrBy ((=="w") . qName))
+
+ let mbpgmar = mbsectpr >>= (filterElementName (wname (=="pgMar")))
+ let mbAttrMarLeft = (elAttribs <$> mbpgmar) >>= (lookupAttrBy ((=="left") . qName))
+ let mbAttrMarRight = (elAttribs <$> mbpgmar) >>= (lookupAttrBy ((=="right") . qName))
+
+ -- Get the avaible area (converting the size and the margins to int and
+ -- doing the difference
+ let pgContentWidth = (-) <$> (read <$> mbAttrSzWidth ::Maybe Integer)
+ <*> (
+ (+) <$> (read <$> mbAttrMarRight ::Maybe Integer)
+ <*> (read <$> mbAttrMarLeft ::Maybe Integer)
+ )
+
+ -- styles
+ let stylepath = "word/styles.xml"
+ styledoc <- parseXml refArchive distArchive stylepath
+
+ -- parse styledoc for heading styles
+ let styleMaps = getStyleMaps styledoc
+
+ let tocTitle = fromMaybe (stTocTitle defaultWriterState) $
+ metaValueToInlines <$> lookupMeta "toc-title" meta
((contents, footnotes), st) <- runStateT (writeOpenXML opts{writerWrapText = False} doc')
defaultWriterState{ stChangesAuthor = fromMaybe "unknown" username
- , stChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime}
+ , stChangesDate = formatTime defaultTimeLocale "%FT%XZ" utctime
+ , stPrintWidth = (maybe 420 (\x -> quot x 20) pgContentWidth)
+ , stStyleMaps = styleMaps
+ , stTocTitle = tocTitle
+ }
let epochtime = floor $ utcTimeToPOSIXSeconds utctime
let imgs = M.elems $ stImages st
@@ -193,9 +260,6 @@ writeDocx opts doc@(Pandoc meta _) = do
let toImageEntry (_,path,_,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
let imageEntries = map toImageEntry imgs
-
-
-
let stdAttributes =
[("xmlns:w","http://schemas.openxmlformats.org/wordprocessingml/2006/main")
,("xmlns:m","http://schemas.openxmlformats.org/officeDocument/2006/math")
@@ -310,10 +374,7 @@ writeDocx opts doc@(Pandoc meta _) = do
$ renderXml reldoc
- -- adjust contents to add sectPr from reference.docx
- parsedDoc <- parseXml refArchive distArchive "word/document.xml"
- let wname f qn = qPrefix qn == Just "w" && f (qName qn)
- let mbsectpr = filterElementName (wname (=="sectPr")) parsedDoc
+ -- adjust contents to add sectPr from reference.docx
let sectpr = case mbsectpr of
Just sectpr' -> let cs = renumIds
(\q -> qName q == "id" && qPrefix q == Just "r")
@@ -323,8 +384,6 @@ writeDocx opts doc@(Pandoc meta _) = do
add_attrs (elAttribs sectpr') $ mknode "w:sectPr" [] cs
Nothing -> (mknode "w:sectPr" [] ())
-
-
-- let sectpr = fromMaybe (mknode "w:sectPr" [] ()) mbsectpr'
let contents' = contents ++ [sectpr]
let docContents = mknode "w:document" stdAttributes
@@ -346,11 +405,18 @@ writeDocx opts doc@(Pandoc meta _) = do
linkrels
-- styles
- let newstyles = styleToOpenXml $ writerHighlightStyle opts
- let stylepath = "word/styles.xml"
- styledoc <- parseXml refArchive distArchive stylepath
- let styledoc' = styledoc{ elContent = elContent styledoc ++
- [Elem x | x <- newstyles, writerHighlight opts] }
+ let newstyles = styleToOpenXml styleMaps $ writerHighlightStyle opts
+ let styledoc' = styledoc{ elContent = modifyContent (elContent styledoc) }
+ where
+ modifyContent
+ | writerHighlight opts = (++ map Elem newstyles)
+ | otherwise = filter notTokStyle
+ notTokStyle (Elem el) = notStyle el || notTokId el
+ notTokStyle _ = True
+ notStyle = (/= elemName' "style") . elName
+ notTokId = maybe True (`notElem` tokStys) . findAttr (elemName' "styleId")
+ tokStys = "SourceCode" : map show (enumFromTo KeywordTok NormalTok)
+ elemName' = elemName (sNameSpaces styleMaps) "w"
let styleEntry = toEntry stylepath epochtime $ renderXml styledoc'
-- construct word/numbering.xml
@@ -395,16 +461,24 @@ writeDocx opts doc@(Pandoc meta _) = do
]
let relsEntry = toEntry relsPath epochtime $ renderXml rels
+ -- we use dist archive for settings.xml, because Word sometimes
+ -- adds references to footnotes or endnotes we don't have...
+ -- we do, however, copy some settings over from reference
+ let settingsPath = "word/settings.xml"
+ settingsList = [ "w:autoHyphenation"
+ , "w:consecutiveHyphenLimit"
+ , "w:hyphenationZone"
+ , "w:doNotHyphenateCap"
+ ]
+ settingsEntry <- copyChildren refArchive distArchive settingsPath epochtime settingsList
+
let entryFromArchive arch path =
- maybe (fail $ path ++ " corrupt or missing in reference docx")
+ maybe (fail $ path ++ " missing in reference docx")
return
(findEntryByPath path arch `mplus` findEntryByPath path distArchive)
docPropsAppEntry <- entryFromArchive refArchive "docProps/app.xml"
themeEntry <- entryFromArchive refArchive "word/theme/theme1.xml"
fontTableEntry <- entryFromArchive refArchive "word/fontTable.xml"
- -- we use dist archive for settings.xml, because Word sometimes
- -- adds references to footnotes or endnotes we don't have...
- settingsEntry <- entryFromArchive distArchive "word/settings.xml"
webSettingsEntry <- entryFromArchive refArchive "word/webSettings.xml"
headerFooterEntries <- mapM (entryFromArchive refArchive) $
mapMaybe (fmap ("word/" ++) . extractTarget)
@@ -427,10 +501,13 @@ writeDocx opts doc@(Pandoc meta _) = do
miscRelEntries ++ otherMediaEntries
return $ fromArchive archive
-styleToOpenXml :: Style -> [Element]
-styleToOpenXml style = parStyle : map toStyle alltoktypes
+styleToOpenXml :: StyleMaps -> Style -> [Element]
+styleToOpenXml sm style =
+ maybeToList parStyle ++ mapMaybe toStyle alltoktypes
where alltoktypes = enumFromTo KeywordTok NormalTok
- toStyle toktype = mknode "w:style" [("w:type","character"),
+ toStyle toktype | hasStyleName (show toktype) (sCharStyleMap sm) = Nothing
+ | otherwise = Just $
+ mknode "w:style" [("w:type","character"),
("w:customStyle","1"),("w:styleId",show toktype)]
[ mknode "w:name" [("w:val",show toktype)] ()
, mknode "w:basedOn" [("w:val","VerbatimChar")] ()
@@ -451,17 +528,35 @@ styleToOpenXml style = parStyle : map toStyle alltoktypes
tokBg toktype = maybe "auto" (drop 1 . fromColor)
$ (tokenBackground =<< lookup toktype tokStyles)
`mplus` backgroundColor style
- parStyle = mknode "w:style" [("w:type","paragraph"),
+ parStyle | hasStyleName "Source Code" (sParaStyleMap sm) = Nothing
+ | otherwise = Just $
+ mknode "w:style" [("w:type","paragraph"),
("w:customStyle","1"),("w:styleId","SourceCode")]
[ mknode "w:name" [("w:val","Source Code")] ()
, mknode "w:basedOn" [("w:val","Normal")] ()
, mknode "w:link" [("w:val","VerbatimChar")] ()
, mknode "w:pPr" []
$ mknode "w:wordWrap" [("w:val","off")] ()
+ : mknode "w:noProof" [] ()
: ( maybe [] (\col -> [mknode "w:shd" [("w:val","clear"),("w:fill",drop 1 $ fromColor col)] ()])
$ backgroundColor style )
]
+copyChildren :: Archive -> Archive -> String -> Integer -> [String] -> IO Entry
+copyChildren refArchive distArchive path timestamp elNames = do
+ ref <- parseXml refArchive distArchive path
+ dist <- parseXml distArchive distArchive path
+ return $ toEntry path timestamp $ renderXml dist{
+ elContent = elContent dist ++ copyContent ref
+ }
+ where
+ strName QName{qName=name, qPrefix=prefix}
+ | Just p <- prefix = p++":"++name
+ | otherwise = name
+ shouldCopy = (`elem` elNames) . strName
+ cleanElem el@Element{elName=name} = Elem el{elName=name{qURI=Nothing}}
+ copyContent = map cleanElem . filterChildrenName shouldCopy
+
-- this is the lowest number used for a list numId
baseListId :: Int
baseListId = 1000
@@ -539,6 +634,34 @@ mkLvl marker lvl =
getNumId :: WS Int
getNumId = (((baseListId - 1) +) . length) `fmap` gets stLists
+makeTOC :: WriterOptions -> WS [Element]
+makeTOC opts | writerTableOfContents opts = do
+ let depth = "1-"++(show (writerTOCDepth opts))
+ let tocCmd = "TOC \\o \""++depth++"\" \\h \\z \\u"
+ tocTitle <- gets stTocTitle
+ title <- withParaPropM (pStyleM "TOC Heading") (blocksToOpenXML opts [Para tocTitle])
+ return $
+ [mknode "w:sdt" [] ([
+ mknode "w:sdtPr" [] (
+ mknode "w:docPartObj" [] (
+ [mknode "w:docPartGallery" [("w:val","Table of Contents")] (),
+ mknode "w:docPartUnique" [] ()]
+ ) -- w:docPartObj
+ ), -- w:sdtPr
+ mknode "w:sdtContent" [] (title++[
+ mknode "w:p" [] (
+ mknode "w:r" [] ([
+ mknode "w:fldChar" [("w:fldCharType","begin"),("w:dirty","true")] (),
+ mknode "w:instrText" [("xml:space","preserve")] tocCmd,
+ mknode "w:fldChar" [("w:fldCharType","separate")] (),
+ mknode "w:fldChar" [("w:fldCharType","end")] ()
+ ]) -- w:r
+ ) -- w:p
+ ])
+ ])] -- w:sdt
+makeTOC _ = return []
+
+
-- | Convert Pandoc document to two lists of
-- OpenXML elements (the main document and footnotes).
writeOpenXML :: WriterOptions -> Pandoc -> WS ([Element], [Element])
@@ -557,32 +680,45 @@ writeOpenXML opts (Pandoc meta blocks) = do
Just (MetaBlocks [Para xs]) -> xs
Just (MetaInlines xs) -> xs
_ -> []
- title <- withParaProp (pStyle "Title") $ blocksToOpenXML opts [Para tit | not (null tit)]
- subtitle <- withParaProp (pStyle "Subtitle") $ blocksToOpenXML opts [Para subtitle' | not (null subtitle')]
- authors <- withParaProp (pStyle "Author") $ blocksToOpenXML opts $
+ title <- withParaPropM (pStyleM "Title") $ blocksToOpenXML opts [Para tit | not (null tit)]
+ subtitle <- withParaPropM (pStyleM "Subtitle") $ blocksToOpenXML opts [Para subtitle' | not (null subtitle')]
+ authors <- withParaProp (pCustomStyle "Author") $ blocksToOpenXML opts $
map Para auths
- date <- withParaProp (pStyle "Date") $ blocksToOpenXML opts [Para dat | not (null dat)]
+ date <- withParaPropM (pStyleM "Date") $ blocksToOpenXML opts [Para dat | not (null dat)]
abstract <- if null abstract'
then return []
- else withParaProp (pStyle "Abstract") $ blocksToOpenXML opts abstract'
+ else withParaProp (pCustomStyle "Abstract") $ blocksToOpenXML opts abstract'
let convertSpace (Str x : Space : Str y : xs) = Str (x ++ " " ++ y) : xs
convertSpace (Str x : Str y : xs) = Str (x ++ y) : xs
convertSpace xs = xs
let blocks' = bottomUp convertSpace blocks
- doc' <- blocksToOpenXML opts blocks'
+ doc' <- (setFirstPara >> blocksToOpenXML opts blocks')
notes' <- reverse `fmap` gets stFootnotes
- let meta' = title ++ subtitle ++ authors ++ date ++ abstract
+ toc <- makeTOC opts
+ let meta' = title ++ subtitle ++ authors ++ date ++ abstract ++ toc
return (meta' ++ doc', notes')
-- | Convert a list of Pandoc blocks to OpenXML.
blocksToOpenXML :: WriterOptions -> [Block] -> WS [Element]
blocksToOpenXML opts bls = concat `fmap` mapM (blockToOpenXML opts) bls
-pStyle :: String -> Element
-pStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
+pCustomStyle :: String -> Element
+pCustomStyle sty = mknode "w:pStyle" [("w:val",sty)] ()
+
+pStyleM :: String -> WS XML.Element
+pStyleM styleName = do
+ styleMaps <- gets stStyleMaps
+ let sty' = getStyleId styleName $ sParaStyleMap styleMaps
+ return $ mknode "w:pStyle" [("w:val",sty')] ()
+
+rCustomStyle :: String -> Element
+rCustomStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
-rStyle :: String -> Element
-rStyle sty = mknode "w:rStyle" [("w:val",sty)] ()
+rStyleM :: String -> WS XML.Element
+rStyleM styleName = do
+ styleMaps <- gets stStyleMaps
+ let sty' = getStyleId styleName $ sCharStyleMap styleMaps
+ return $ mknode "w:rStyle" [("w:val",sty')] ()
getUniqueId :: MonadIO m => m String
-- the + 20 is to ensure that there are no clashes with the rIds
@@ -596,12 +732,13 @@ blockToOpenXML opts (Div (_,["references"],_) bs) = do
let (hs, bs') = span isHeaderBlock bs
header <- blocksToOpenXML opts hs
-- We put the Bibliography style on paragraphs after the header
- rest <- withParaProp (pStyle "Bibliography") $ blocksToOpenXML opts bs'
+ rest <- withParaPropM (pStyleM "Bibliography") $ blocksToOpenXML opts bs'
return (header ++ rest)
blockToOpenXML opts (Div _ bs) = blocksToOpenXML opts bs
blockToOpenXML opts (Header lev (ident,_,_) lst) = do
- paraProps <- withParaProp (pStyle $ "Heading" ++ show lev) $
- getParaProps False
+ setFirstPara
+ paraProps <- withParaPropM (pStyleM ("Heading "++show lev)) $
+ getParaProps False
contents <- inlinesToOpenXML opts lst
usedIdents <- gets stSectionIds
let bookmarkName = if null ident
@@ -613,40 +750,60 @@ blockToOpenXML opts (Header lev (ident,_,_) lst) = do
,("w:name",bookmarkName)] ()
let bookmarkEnd = mknode "w:bookmarkEnd" [("w:id", id')] ()
return [mknode "w:p" [] (paraProps ++ [bookmarkStart, bookmarkEnd] ++ contents)]
-blockToOpenXML opts (Plain lst) = withParaProp (pStyle "Compact")
+blockToOpenXML opts (Plain lst) = withParaProp (pCustomStyle "Compact")
$ blockToOpenXML opts (Para lst)
-- title beginning with fig: indicates that the image is a figure
blockToOpenXML opts (Para [Image alt (src,'f':'i':'g':':':tit)]) = do
+ setFirstPara
+ pushParaProp $ pCustomStyle $
+ if null alt
+ then "Figure"
+ else "FigureWithCaption"
paraProps <- getParaProps False
+ popParaProp
contents <- inlinesToOpenXML opts [Image alt (src,tit)]
- captionNode <- withParaProp (pStyle "ImageCaption")
+ captionNode <- withParaProp (pCustomStyle "ImageCaption")
$ blockToOpenXML opts (Para alt)
return $ mknode "w:p" [] (paraProps ++ contents) : captionNode
-- fixDisplayMath sometimes produces a Para [] as artifact
blockToOpenXML _ (Para []) = return []
blockToOpenXML opts (Para lst) = do
- paraProps <- getParaProps $ case lst of
- [Math DisplayMath _] -> True
- _ -> False
- contents <- inlinesToOpenXML opts lst
- return [mknode "w:p" [] (paraProps ++ contents)]
+ isFirstPara <- gets stFirstPara
+ paraProps <- getParaProps $ case lst of
+ [Math DisplayMath _] -> True
+ _ -> False
+ bodyTextStyle <- pStyleM "Body Text"
+ let paraProps' = case paraProps of
+ [] | isFirstPara -> [mknode "w:pPr" [] [pCustomStyle "FirstParagraph"]]
+ [] -> [mknode "w:pPr" [] [bodyTextStyle]]
+ ps -> ps
+ modify $ \s -> s { stFirstPara = False }
+ contents <- inlinesToOpenXML opts lst
+ return [mknode "w:p" [] (paraProps' ++ contents)]
blockToOpenXML _ (RawBlock format str)
| format == Format "openxml" = return [ x | Elem x <- parseXML str ]
| otherwise = return []
-blockToOpenXML opts (BlockQuote blocks) =
- withParaProp (pStyle "BlockQuote") $ blocksToOpenXML opts blocks
-blockToOpenXML opts (CodeBlock attrs str) =
- withParaProp (pStyle "SourceCode") $ blockToOpenXML opts $ Para [Code attrs str]
-blockToOpenXML _ HorizontalRule = return [
- mknode "w:p" [] $ mknode "w:r" [] $ mknode "w:pict" []
+blockToOpenXML opts (BlockQuote blocks) = do
+ p <- withParaPropM (pStyleM "Block Text") $ blocksToOpenXML opts blocks
+ setFirstPara
+ return p
+blockToOpenXML opts (CodeBlock attrs str) = do
+ p <- withParaProp (pCustomStyle "SourceCode") (blockToOpenXML opts $ Para [Code attrs str])
+ setFirstPara
+ return p
+blockToOpenXML _ HorizontalRule = do
+ setFirstPara
+ return [
+ mknode "w:p" [] $ mknode "w:r" [] $ mknode "w:pict" []
$ mknode "v:rect" [("style","width:0;height:1.5pt"),
("o:hralign","center"),
("o:hrstd","t"),("o:hr","t")] () ]
blockToOpenXML opts (Table caption aligns widths headers rows) = do
+ setFirstPara
let captionStr = stringify caption
caption' <- if null caption
then return []
- else withParaProp (pStyle "TableCaption")
+ else withParaProp (pCustomStyle "TableCaption")
$ blockToOpenXML opts (Para caption)
let alignmentFor al = mknode "w:jc" [("w:val",alignmentToString al)] ()
let cellToOpenXML (al, cell) = withParaProp (alignmentFor al)
@@ -657,51 +814,62 @@ blockToOpenXML opts (Table caption aligns widths headers rows) = do
[ mknode "w:tcBorders" []
$ mknode "w:bottom" [("w:val","single")] ()
, mknode "w:vAlign" [("w:val","bottom")] () ]
- let emptyCell = [mknode "w:p" [] [mknode "w:pPr" []
- [mknode "w:pStyle" [("w:val","Compact")] ()]]]
+ let emptyCell = [mknode "w:p" [] [pCustomStyle "Compact"]]
let mkcell border contents = mknode "w:tc" []
$ [ borderProps | border ] ++
if null contents
then emptyCell
else contents
- let mkrow border cells = mknode "w:tr" [] $ map (mkcell border) cells
+ let mkrow border cells = mknode "w:tr" [] $
+ [mknode "w:trPr" [] [
+ mknode "w:cnfStyle" [("w:firstRow","1")] ()] | border]
+ ++ map (mkcell border) cells
let textwidth = 7920 -- 5.5 in in twips, 1/20 pt
let fullrow = 5000 -- 100% specified in pct
let rowwidth = fullrow * sum widths
let mkgridcol w = mknode "w:gridCol"
[("w:w", show (floor (textwidth * w) :: Integer))] ()
+ let hasHeader = not (all null headers)
return $
- mknode "w:tbl" []
+ caption' ++
+ [mknode "w:tbl" []
( mknode "w:tblPr" []
( mknode "w:tblStyle" [("w:val","TableNormal")] () :
mknode "w:tblW" [("w:type", "pct"), ("w:w", show rowwidth)] () :
+ mknode "w:tblLook" [("w:firstRow","1") | hasHeader ] () :
[ mknode "w:tblCaption" [("w:val", captionStr)] ()
| not (null caption) ] )
: mknode "w:tblGrid" []
(if all (==0) widths
then []
else map mkgridcol widths)
- : [ mkrow True headers' | not (all null headers) ] ++
+ : [ mkrow True headers' | hasHeader ] ++
map (mkrow False) rows'
- ) : caption'
+ )]
blockToOpenXML opts (BulletList lst) = do
let marker = BulletMarker
addList marker
numid <- getNumId
- asList $ concat `fmap` mapM (listItemToOpenXML opts numid) lst
+ l <- asList $ concat `fmap` mapM (listItemToOpenXML opts numid) lst
+ setFirstPara
+ return l
blockToOpenXML opts (OrderedList (start, numstyle, numdelim) lst) = do
let marker = NumberMarker numstyle numdelim start
addList marker
numid <- getNumId
- asList $ concat `fmap` mapM (listItemToOpenXML opts numid) lst
-blockToOpenXML opts (DefinitionList items) =
- concat `fmap` mapM (definitionListItemToOpenXML opts) items
+ l <- asList $ concat `fmap` mapM (listItemToOpenXML opts numid) lst
+ setFirstPara
+ return l
+blockToOpenXML opts (DefinitionList items) = do
+ l <- concat `fmap` mapM (definitionListItemToOpenXML opts) items
+ setFirstPara
+ return l
definitionListItemToOpenXML :: WriterOptions -> ([Inline],[[Block]]) -> WS [Element]
definitionListItemToOpenXML opts (term,defs) = do
- term' <- withParaProp (pStyle "DefinitionTerm")
+ term' <- withParaProp (pCustomStyle "DefinitionTerm")
$ blockToOpenXML opts (Para term)
- defs' <- withParaProp (pStyle "Definition")
+ defs' <- withParaProp (pCustomStyle "Definition")
$ concat `fmap` mapM (blocksToOpenXML opts) defs
return $ term' ++ defs'
@@ -765,6 +933,9 @@ withTextProp d p = do
popTextProp
return res
+withTextPropM :: WS Element -> WS a -> WS a
+withTextPropM = (. flip withTextProp) . (>>=)
+
getParaProps :: Bool -> WS [Element]
getParaProps displayMathPara = do
props <- gets stParaProperties
@@ -793,6 +964,9 @@ withParaProp d p = do
popParaProp
return res
+withParaPropM :: WS Element -> WS a -> WS a
+withParaPropM = (. flip withParaProp) . (>>=)
+
formattedString :: String -> WS [Element]
formattedString str = do
props <- getTextProps
@@ -802,6 +976,9 @@ formattedString str = do
[ mknode (if inDel then "w:delText" else "w:t")
[("xml:space","preserve")] str ] ]
+setFirstPara :: WS ()
+setFirstPara = modify $ \s -> s { stFirstPara = True }
+
-- | Convert an inline element to OpenXML.
inlineToOpenXML :: WriterOptions -> Inline -> WS [Element]
inlineToOpenXML _ (Str str) = formattedString str
@@ -872,25 +1049,26 @@ inlineToOpenXML opts (Math mathType str) = do
Right r -> return [r]
Left _ -> inlinesToOpenXML opts (texMathToInlines mathType str)
inlineToOpenXML opts (Cite _ lst) = inlinesToOpenXML opts lst
-inlineToOpenXML opts (Code attrs str) =
- withTextProp (rStyle "VerbatimChar")
- $ if writerHighlight opts
- then case highlight formatOpenXML attrs str of
- Nothing -> unhighlighted
- Just h -> return h
- else unhighlighted
- where unhighlighted = intercalate [br] `fmap`
- (mapM formattedString $ lines str)
- formatOpenXML _fmtOpts = intercalate [br] . map (map toHlTok)
- toHlTok (toktype,tok) = mknode "w:r" []
- [ mknode "w:rPr" []
- [ rStyle $ show toktype ]
- , mknode "w:t" [("xml:space","preserve")] tok ]
+inlineToOpenXML opts (Code attrs str) = do
+ let unhighlighted = intercalate [br] `fmap`
+ (mapM formattedString $ lines str)
+ formatOpenXML _fmtOpts = intercalate [br] . map (map toHlTok)
+ toHlTok (toktype,tok) = mknode "w:r" []
+ [ mknode "w:rPr" []
+ [ rCustomStyle (show toktype) ]
+ , mknode "w:t" [("xml:space","preserve")] tok ]
+ withTextProp (rCustomStyle "VerbatimChar")
+ $ if writerHighlight opts
+ then case highlight formatOpenXML attrs str of
+ Nothing -> unhighlighted
+ Just h -> return h
+ else unhighlighted
inlineToOpenXML opts (Note bs) = do
notes <- gets stFootnotes
notenum <- getUniqueId
+ footnoteStyle <- rStyleM "Footnote Reference"
let notemarker = mknode "w:r" []
- [ mknode "w:rPr" [] (rStyle "FootnoteRef")
+ [ mknode "w:rPr" [] footnoteStyle
, mknode "w:footnoteRef" [] () ]
let notemarkerXml = RawInline (Format "openxml") $ ppElement notemarker
let insertNoteRef (Plain ils : xs) = Plain (notemarkerXml : ils) : xs
@@ -900,22 +1078,22 @@ inlineToOpenXML opts (Note bs) = do
oldParaProperties <- gets stParaProperties
oldTextProperties <- gets stTextProperties
modify $ \st -> st{ stListLevel = -1, stParaProperties = [], stTextProperties = [] }
- contents <- withParaProp (pStyle "FootnoteText") $ blocksToOpenXML opts
+ contents <- withParaPropM (pStyleM "Footnote Text") $ blocksToOpenXML opts
$ insertNoteRef bs
modify $ \st -> st{ stListLevel = oldListLevel, stParaProperties = oldParaProperties,
stTextProperties = oldTextProperties }
let newnote = mknode "w:footnote" [("w:id", notenum)] $ contents
modify $ \s -> s{ stFootnotes = newnote : notes }
return [ mknode "w:r" []
- [ mknode "w:rPr" [] (rStyle "FootnoteRef")
+ [ mknode "w:rPr" [] footnoteStyle
, mknode "w:footnoteReference" [("w:id", notenum)] () ] ]
-- internal link:
inlineToOpenXML opts (Link txt ('#':xs,_)) = do
- contents <- withTextProp (rStyle "Link") $ inlinesToOpenXML opts txt
+ contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
return [ mknode "w:hyperlink" [("w:anchor",xs)] contents ]
-- external link:
inlineToOpenXML opts (Link txt (src,_)) = do
- contents <- withTextProp (rStyle "Link") $ inlinesToOpenXML opts txt
+ contents <- withTextPropM (rStyleM "Hyperlink") $ inlinesToOpenXML opts txt
extlinks <- gets stExternalLinks
id' <- case M.lookup src extlinks of
Just i -> return i
@@ -927,6 +1105,7 @@ inlineToOpenXML opts (Link txt (src,_)) = do
return [ mknode "w:hyperlink" [("r:id",id')] contents ]
inlineToOpenXML opts (Image alt (src, tit)) = do
-- first, check to see if we've already done this image
+ pageWidth <- gets stPrintWidth
imgs <- gets stImages
case M.lookup src imgs of
Just (_,_,_,elt,_) -> return [elt]
@@ -940,10 +1119,15 @@ inlineToOpenXML opts (Image alt (src, tit)) = do
inlinesToOpenXML opts alt
Right (img, mt) -> do
ident <- ("rId"++) `fmap` getUniqueId
- let size = imageSize img
- let (xpt,ypt) = maybe (120,120) sizeInPoints size
+ (xpt,ypt) <- case imageSize img of
+ Right size -> return $ sizeInPoints size
+ Left msg -> do
+ liftIO $ warn $
+ "Could not determine image size in `" ++
+ src ++ "': " ++ msg
+ return (120,120)
-- 12700 emu = 1 pt
- let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
+ let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700) (pageWidth * 12700)
let cNvPicPr = mknode "pic:cNvPicPr" [] $
mknode "a:picLocks" [("noChangeArrowheads","1"),("noChangeAspect","1")] ()
let nvPicPr = mknode "pic:nvPicPr" []
@@ -1001,18 +1185,38 @@ inlineToOpenXML opts (Image alt (src, tit)) = do
br :: Element
br = mknode "w:r" [] [mknode "w:br" [("w:type","textWrapping")] () ]
+-- Word will insert these footnotes into the settings.xml file
+-- (whether or not they're visible in the document). If they're in the
+-- file, but not in the footnotes.xml file, it will produce
+-- problems. So we want to make sure we insert them into our document.
+defaultFootnotes :: [Element]
+defaultFootnotes = [ mknode "w:footnote"
+ [("w:type", "separator"), ("w:id", "-1")] $
+ [ mknode "w:p" [] $
+ [mknode "w:r" [] $
+ [ mknode "w:separator" [] ()]]]
+ , mknode "w:footnote"
+ [("w:type", "continuationSeparator"), ("w:id", "0")] $
+ [ mknode "w:p" [] $
+ [ mknode "w:r" [] $
+ [ mknode "w:continuationSeparator" [] ()]]]]
+
parseXml :: Archive -> Archive -> String -> IO Element
parseXml refArchive distArchive relpath =
- case ((findEntryByPath relpath refArchive `mplus`
- findEntryByPath relpath distArchive)
- >>= parseXMLDoc . UTF8.toStringLazy . fromEntry) of
- Just d -> return d
- Nothing -> fail $ relpath ++ " corrupt or missing in reference docx"
+ case findEntryByPath relpath refArchive `mplus`
+ findEntryByPath relpath distArchive of
+ Nothing -> fail $ relpath ++ " missing in reference docx"
+ Just e -> case parseXMLDoc . UTF8.toStringLazy . fromEntry $ e of
+ Nothing -> fail $ relpath ++ " corrupt in reference docx"
+ Just d -> return d
-- | Scales the image to fit the page
-fitToPage :: (Integer, Integer) -> (Integer, Integer)
-fitToPage (x, y)
- --5440680 is the emu width size of a letter page in portrait, minus the margins
- | x > 5440680 =
- (5440680, round $ (5440680 / ((fromIntegral :: Integer -> Double) x)) * (fromIntegral y))
+-- sizes are passed in emu
+fitToPage :: (Integer, Integer) -> Integer -> (Integer, Integer)
+fitToPage (x, y) pageWidth
+ -- Fixes width to the page width and scales the height
+ | x > pageWidth =
+ (pageWidth, round $
+ ((fromIntegral pageWidth) / ((fromIntegral :: Integer -> Double) x)) * (fromIntegral y))
| otherwise = (x, y)
+
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index 8c1d360aa..7ebe09db7 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.DokuWiki
- Copyright : Copyright (C) 2008-2014 John MacFarlane
+ Copyright : Copyright (C) 2008-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Clare Macrae <clare.macrae@googlemail.com>
@@ -134,7 +134,9 @@ blockToDokuWiki opts (Para [Image txt (src,'f':'i':'g':':':tit)]) = do
let opt = if null txt
then ""
else "|" ++ if null tit then capt else tit ++ capt
- return $ "{{:" ++ src ++ opt ++ "}}\n"
+ -- Relative links fail isURI and receive a colon
+ prefix = if isURI src then "" else ":"
+ return $ "{{" ++ prefix ++ src ++ opt ++ "}}\n"
blockToDokuWiki opts (Para inlines) = do
indent <- stIndent <$> ask
@@ -170,15 +172,15 @@ blockToDokuWiki _ (CodeBlock (_,classes,_) str) = do
"python", "qbasic", "rails", "reg", "robots", "ruby", "sas", "scheme", "sdlbasic",
"smalltalk", "smarty", "sql", "tcl", "", "thinbasic", "tsql", "vb", "vbnet", "vhdl",
"visualfoxpro", "winbatch", "xml", "xpp", "z80"]
- let (beg, end) = if null at
- then ("<code" ++ if null classes then ">" else " class=\"" ++ unwords classes ++ "\">", "</code>")
- else ("<source lang=\"" ++ head at ++ "\">", "</source>")
- return $ beg ++ str ++ end
+ return $ "<code" ++
+ (case at of
+ [] -> ">\n"
+ (x:_) -> " " ++ x ++ ">\n") ++ str ++ "\n</code>"
blockToDokuWiki opts (BlockQuote blocks) = do
contents <- blockListToDokuWiki opts blocks
if isSimpleBlockQuote blocks
- then return $ "> " ++ contents
+ then return $ unlines $ map ("> " ++) $ lines contents
else return $ "<HTML><blockquote>\n" ++ contents ++ "</blockquote></HTML>"
blockToDokuWiki opts (Table capt aligns _ headers rows) = do
@@ -352,9 +354,7 @@ isPlainOrPara (Para _) = True
isPlainOrPara _ = False
isSimpleBlockQuote :: [Block] -> Bool
-isSimpleBlockQuote [BlockQuote bs] = isSimpleBlockQuote bs
-isSimpleBlockQuote [b] = isPlainOrPara b
-isSimpleBlockQuote _ = False
+isSimpleBlockQuote bs = all isPlainOrPara bs
-- | Concatenates strings with line breaks between them.
vcat :: [String] -> String
@@ -451,7 +451,7 @@ inlineToDokuWiki _ (Code _ str) =
inlineToDokuWiki _ (Str str) = return $ escapeString str
-inlineToDokuWiki _ (Math _ str) = return $ "<math>" ++ str ++ "</math>"
+inlineToDokuWiki _ (Math _ str) = return $ "$" ++ str ++ "$"
-- note: str should NOT be escaped
inlineToDokuWiki _ (RawInline f str)
@@ -459,7 +459,7 @@ inlineToDokuWiki _ (RawInline f str)
| f == Format "html" = return $ "<html>" ++ str ++ "</html>"
| otherwise = return ""
-inlineToDokuWiki _ (LineBreak) = return "\\\\ "
+inlineToDokuWiki _ (LineBreak) = return "\\\\\n"
inlineToDokuWiki _ Space = return " "
@@ -480,7 +480,9 @@ inlineToDokuWiki opts (Image alt (source, tit)) = do
("", []) -> ""
("", _ ) -> "|" ++ alt'
(_ , _ ) -> "|" ++ tit
- return $ "{{:" ++ source ++ txt ++ "}}"
+ -- Relative links fail isURI and receive a colon
+ prefix = if isURI source then "" else ":"
+ return $ "{{" ++ prefix ++ source ++ txt ++ "}}"
inlineToDokuWiki opts (Note contents) = do
contents' <- blockListToDokuWiki opts contents
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index 53574711f..8577c0fa2 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -1,6 +1,6 @@
-{-# LANGUAGE PatternGuards, CPP, ScopedTypeVariables, ViewPatterns #-}
+{-# LANGUAGE PatternGuards, CPP, ScopedTypeVariables, ViewPatterns, FlexibleContexts #-}
{-
-Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.EPUB
- Copyright : Copyright (C) 2010-2014 John MacFarlane
+ Copyright : Copyright (C) 2010-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,11 +31,12 @@ Conversion of 'Pandoc' documents to EPUB.
module Text.Pandoc.Writers.EPUB ( writeEPUB ) where
import Data.IORef ( IORef, newIORef, readIORef, modifyIORef )
import qualified Data.Map as M
-import Data.Maybe ( fromMaybe )
+import Data.Maybe ( fromMaybe, catMaybes )
import Data.List ( isPrefixOf, isInfixOf, intercalate )
import System.Environment ( getEnv )
import Text.Printf (printf)
import System.FilePath ( takeExtension, takeFileName )
+import System.FilePath.Glob ( namesMatching )
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as B8
import qualified Text.Pandoc.UTF8 as UTF8
@@ -44,7 +45,7 @@ import Codec.Archive.Zip ( emptyArchive, addEntryToArchive, eRelativePath, fromE
import Control.Applicative ((<$>))
import Data.Time.Clock.POSIX ( getPOSIXTime )
import Data.Time (getCurrentTime,UTCTime, formatTime)
-import System.Locale ( defaultTimeLocale )
+import Text.Pandoc.Compat.Locale ( defaultTimeLocale )
import Text.Pandoc.Shared ( trimr, renderTags', safeRead, uniqueIdent, trim
, normalizeDate, readDataFile, stringify, warn
, hierarchicalize, fetchItem' )
@@ -55,16 +56,18 @@ import Text.Pandoc.Options ( WriterOptions(..)
, EPUBVersion(..)
, ObfuscationMethod(NoObfuscation) )
import Text.Pandoc.Definition
-import Text.Pandoc.Walk (walk, walkM)
-import Control.Monad.State (modify, get, execState, State, put, evalState)
-import Control.Monad (foldM, when, mplus, liftM)
+import Text.Pandoc.Walk (walk, walkM, query)
+import Data.Default
+import Text.Pandoc.Writers.Markdown (writePlain)
+import Control.Monad.State (modify, get, State, put, evalState)
+import Control.Monad (mplus, liftM, when)
import Text.XML.Light ( unode, Element(..), unqual, Attr(..), add_attrs
, strContent, lookupAttr, Node(..), QName(..), parseXML
, onlyElems, node, ppElement)
import Text.Pandoc.UUID (getRandomUUID)
import Text.Pandoc.Writers.HTML (writeHtmlString, writeHtml)
import Data.Char ( toLower, isDigit, isAlphaNum )
-import Text.Pandoc.MIME (MimeType, getMimeType)
+import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
import qualified Control.Exception as E
import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
import Text.HTML.TagSoup (Tag(TagOpen), fromAttrib, parseTags)
@@ -225,8 +228,9 @@ addMetadataFromXML _ md = md
metaValueToString :: MetaValue -> String
metaValueToString (MetaString s) = s
-metaValueToString (MetaInlines ils) = stringify ils
-metaValueToString (MetaBlocks bs) = stringify bs
+metaValueToString (MetaInlines ils) = writePlain def
+ (Pandoc nullMeta [Plain ils])
+metaValueToString (MetaBlocks bs) = writePlain def (Pandoc nullMeta bs)
metaValueToString (MetaBool b) = show b
metaValueToString _ = ""
@@ -343,7 +347,6 @@ writeEPUB opts doc@(Pandoc meta _) = do
, writerStandalone = True
, writerSectionDivs = True
, writerHtml5 = epub3
- , writerTableOfContents = False -- we always have one in epub
, writerVariables = vars
, writerHTMLMathMethod =
if epub3
@@ -358,8 +361,9 @@ writeEPUB opts doc@(Pandoc meta _) = do
Nothing -> return ([],[])
Just img -> do
let coverImage = "media/" ++ takeFileName img
- let cpContent = renderHtml $ writeHtml opts'
- (Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
+ let cpContent = renderHtml $ writeHtml
+ opts'{ writerVariables = ("coverpage","true"):vars }
+ (Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
imgContent <- B.readFile img
return ( [mkEntry "cover.xhtml" cpContent]
, [mkEntry coverImage imgContent] )
@@ -374,21 +378,17 @@ writeEPUB opts doc@(Pandoc meta _) = do
mediaRef <- newIORef []
Pandoc _ blocks <- walkM (transformInline opts' mediaRef) doc >>=
walkM (transformBlock opts' mediaRef)
- pics <- readIORef mediaRef
- let readPicEntry entries (oldsrc, newsrc) = do
- res <- fetchItem' (writerMediaBag opts')
- (writerSourceURL opts') oldsrc
- case res of
- Left _ -> do
- warn $ "Could not find media `" ++ oldsrc ++ "', skipping..."
- return entries
- Right (img,_) -> return $
- (toEntry newsrc epochtime $ B.fromChunks . (:[]) $ img) : entries
- picEntries <- foldM readPicEntry [] pics
+ picEntries <- (catMaybes . map (snd . snd)) <$> readIORef mediaRef
-- handle fonts
+ let matchingGlob f = do
+ xs <- namesMatching f
+ when (null xs) $
+ warn $ f ++ " did not match any font files."
+ return xs
let mkFontEntry f = mkEntry (takeFileName f) `fmap` B.readFile f
- fontEntries <- mapM mkFontEntry $ writerEpubFonts opts'
+ fontFiles <- concat <$> mapM matchingGlob (writerEpubFonts opts')
+ fontEntries <- mapM mkFontEntry fontFiles
-- set page progression direction attribution
let progressionDirection = case epubPageDirection metadata of
@@ -408,17 +408,16 @@ writeEPUB opts doc@(Pandoc meta _) = do
(docTitle' meta) : blocks
let chapterHeaderLevel = writerEpubChapterLevel opts
- -- internal reference IDs change when we chunk the file,
- -- so that '#my-header-1' might turn into 'chap004.xhtml#my-header'.
- -- the next two lines fix that:
- let reftable = correlateRefs chapterHeaderLevel blocks'
- let blocks'' = replaceRefs reftable blocks'
let isChapterHeader (Header n _ _) = n <= chapterHeaderLevel
+ isChapterHeader (Div ("",["references"],[]) (Header n _ _:_)) =
+ n <= chapterHeaderLevel
isChapterHeader _ = False
let toChapters :: [Block] -> State [Int] [Chapter]
toChapters [] = return []
+ toChapters (Div ("",["references"],[]) bs@(Header 1 _ _:_) : rest) =
+ toChapters (bs ++ rest)
toChapters (Header n attr@(_,classes,_) ils : bs) = do
nums <- get
mbnum <- if "unnumbered" `elem` classes
@@ -439,7 +438,37 @@ writeEPUB opts doc@(Pandoc meta _) = do
let (xs,ys) = break isChapterHeader bs
(Chapter Nothing (b:xs) :) `fmap` toChapters ys
- let chapters = evalState (toChapters blocks'') []
+ let chapters' = evalState (toChapters blocks') []
+
+ let extractLinkURL' :: Int -> Inline -> [(String, String)]
+ extractLinkURL' num (Span (ident, _, _) _)
+ | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ extractLinkURL' _ _ = []
+
+ let extractLinkURL :: Int -> Block -> [(String, String)]
+ extractLinkURL num (Div (ident, _, _) _)
+ | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ extractLinkURL num (Header _ (ident, _, _) _)
+ | not (null ident) = [(ident, showChapter num ++ ('#':ident))]
+ extractLinkURL num b = query (extractLinkURL' num) b
+
+ let reftable = concat $ zipWith (\(Chapter _ bs) num ->
+ query (extractLinkURL num) bs)
+ chapters' [1..]
+
+ let fixInternalReferences :: Inline -> Inline
+ fixInternalReferences (Link lab ('#':xs, tit)) =
+ case lookup xs reftable of
+ Just ys -> Link lab (ys, tit)
+ Nothing -> Link lab ('#':xs, tit)
+ fixInternalReferences x = x
+
+ -- internal reference IDs change when we chunk the file,
+ -- so that '#my-header-1' might turn into 'chap004.xhtml#my-header'.
+ -- this fixes that:
+ let chapters = map (\(Chapter mbnum bs) ->
+ Chapter mbnum $ walk fixInternalReferences bs)
+ chapters'
let chapToEntry :: Int -> Chapter -> Entry
chapToEntry num (Chapter mbnum bs) = mkEntry (showChapter num)
@@ -488,6 +517,9 @@ writeEPUB opts doc@(Pandoc meta _) = do
[] -> "UNTITLED"
(x:_) -> titleText x
x -> stringify x
+
+ let tocTitle = fromMaybe plainTitle $
+ metaValueToString <$> lookupMeta "toc-title" meta
let uuid = case epubIdentifier metadata of
(x:_) -> identifierText x -- use first identifier as UUID
[] -> error "epubIdentifier is null" -- shouldn't happen
@@ -521,7 +553,7 @@ writeEPUB opts doc@(Pandoc meta _) = do
case epubCoverImage metadata of
Nothing -> []
Just _ -> [ unode "itemref" !
- [("idref", "cover_xhtml"),("linear","no")] $ () ]
+ [("idref", "cover_xhtml")] $ () ]
++ ((unode "itemref" ! [("idref", "title_page_xhtml")
,("linear",
case lookupMeta "title" meta of
@@ -532,7 +564,7 @@ writeEPUB opts doc@(Pandoc meta _) = do
map chapterRefNode chapterEntries)
, unode "guide" $
[ unode "reference" !
- [("type","toc"),("title",plainTitle),
+ [("type","toc"),("title", tocTitle),
("href","nav.xhtml")] $ ()
] ++
[ unode "reference" !
@@ -542,7 +574,7 @@ writeEPUB opts doc@(Pandoc meta _) = do
let contentsEntry = mkEntry "content.opf" contentsData
-- toc.ncx
- let secs = hierarchicalize blocks''
+ let secs = hierarchicalize blocks'
let tocLevel = writerTOCDepth opts
@@ -569,8 +601,7 @@ writeEPUB opts doc@(Pandoc meta _) = do
let navMapFormatter :: Int -> String -> String -> [Element] -> Element
navMapFormatter n tit src subs = unode "navPoint" !
- [("id", "navPoint-" ++ show n)
- ,("playOrder", show n)] $
+ [("id", "navPoint-" ++ show n)] $
[ unode "navLabel" $ unode "text" tit
, unode "content" ! [("src", src)] $ ()
] ++ subs
@@ -611,17 +642,35 @@ writeEPUB opts doc@(Pandoc meta _) = do
(_:_) -> [unode "ol" ! [("class","toc")] $ subs]
let navtag = if epub3 then "nav" else "div"
- let navData = UTF8.fromStringLazy $ ppTopElement $
- unode "html" ! [("xmlns","http://www.w3.org/1999/xhtml")
- ,("xmlns:epub","http://www.idpf.org/2007/ops")] $
- [ unode "head" $
- [ unode "title" plainTitle
- , unode "link" ! [("rel","stylesheet"),("type","text/css"),("href","stylesheet.css")] $ () ]
- , unode "body" $
- unode navtag ! [("epub:type","toc") | epub3] $
- [ unode "h1" ! [("id","toc-title")] $ plainTitle
- , unode "ol" ! [("class","toc")] $ evalState (mapM (navPointNode navXhtmlFormatter) secs) 1]
- ]
+ let navBlocks = [RawBlock (Format "html") $ ppElement $
+ unode navtag ! ([("epub:type","toc") | epub3] ++
+ [("id","toc")]) $
+ [ unode "h1" ! [("id","toc-title")] $ tocTitle
+ , unode "ol" ! [("class","toc")] $ evalState (mapM (navPointNode navXhtmlFormatter) secs) 1]]
+ let landmarks = if epub3
+ then [RawBlock (Format "html") $ ppElement $
+ unode "nav" ! [("epub:type","landmarks")
+ ,("hidden","hidden")] $
+ [ unode "ol" $
+ [ unode "li"
+ [ unode "a" ! [("href", "cover.xhtml")
+ ,("epub:type", "cover")] $
+ "Cover"] |
+ epubCoverImage metadata /= Nothing
+ ] ++
+ [ unode "li"
+ [ unode "a" ! [("href", "#toc")
+ ,("epub:type", "toc")] $
+ "Table of contents"
+ ] | writerTableOfContents opts
+ ]
+ ]
+ ]
+ else []
+ let navData = renderHtml $ writeHtml opts'
+ (Pandoc (setMeta "title"
+ (walk removeNote $ fromList $ docTitle' meta) nullMeta)
+ (navBlocks ++ landmarks))
let navEntry = mkEntry "nav.xhtml" navData
-- mimetype
@@ -764,59 +813,75 @@ metadataElement version md currentTime =
showDateTimeISO8601 :: UTCTime -> String
showDateTimeISO8601 = formatTime defaultTimeLocale "%FT%TZ"
-transformTag :: IORef [(FilePath, FilePath)] -- ^ (oldpath, newpath) media
+transformTag :: WriterOptions
+ -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media
-> Tag String
-> IO (Tag String)
-transformTag mediaRef tag@(TagOpen name attr)
+transformTag opts mediaRef tag@(TagOpen name attr)
| name `elem` ["video", "source", "img", "audio"] = do
let src = fromAttrib "src" tag
let poster = fromAttrib "poster" tag
- newsrc <- modifyMediaRef mediaRef src
- newposter <- modifyMediaRef mediaRef poster
+ newsrc <- modifyMediaRef opts mediaRef src
+ newposter <- modifyMediaRef opts mediaRef poster
let attr' = filter (\(x,_) -> x /= "src" && x /= "poster") attr ++
[("src", newsrc) | not (null newsrc)] ++
[("poster", newposter) | not (null newposter)]
return $ TagOpen name attr'
-transformTag _ tag = return tag
-
-modifyMediaRef :: IORef [(FilePath, FilePath)] -> FilePath -> IO FilePath
-modifyMediaRef _ "" = return ""
-modifyMediaRef mediaRef oldsrc = do
+transformTag _ _ tag = return tag
+
+modifyMediaRef :: WriterOptions
+ -> IORef [(FilePath, (FilePath, Maybe Entry))]
+ -> FilePath
+ -> IO FilePath
+modifyMediaRef _ _ "" = return ""
+modifyMediaRef opts mediaRef oldsrc = do
media <- readIORef mediaRef
case lookup oldsrc media of
- Just n -> return n
- Nothing -> do
- let new = "media/file" ++ show (length media) ++
- takeExtension (takeWhile (/='?') oldsrc) -- remove query
- modifyIORef mediaRef ( (oldsrc, new): )
+ Just (n,_) -> return n
+ Nothing -> do
+ res <- fetchItem' (writerMediaBag opts)
+ (writerSourceURL opts) oldsrc
+ (new, mbEntry) <-
+ case res of
+ Left _ -> do
+ warn $ "Could not find media `" ++ oldsrc ++ "', skipping..."
+ return (oldsrc, Nothing)
+ Right (img,mbMime) -> do
+ let new = "media/file" ++ show (length media) ++
+ fromMaybe (takeExtension (takeWhile (/='?') oldsrc))
+ (('.':) <$> (mbMime >>= extensionFromMimeType))
+ epochtime <- floor `fmap` getPOSIXTime
+ let entry = toEntry new epochtime $ B.fromChunks . (:[]) $ img
+ return (new, Just entry)
+ modifyIORef mediaRef ( (oldsrc, (new, mbEntry)): )
return new
transformBlock :: WriterOptions
- -> IORef [(FilePath, FilePath)] -- ^ (oldpath, newpath) media
+ -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath, entry) media
-> Block
-> IO Block
-transformBlock _ mediaRef (RawBlock fmt raw)
+transformBlock opts mediaRef (RawBlock fmt raw)
| fmt == Format "html" = do
let tags = parseTags raw
- tags' <- mapM (transformTag mediaRef) tags
+ tags' <- mapM (transformTag opts mediaRef) tags
return $ RawBlock fmt (renderTags' tags')
transformBlock _ _ b = return b
transformInline :: WriterOptions
- -> IORef [(FilePath, FilePath)] -- ^ (oldpath, newpath) media
+ -> IORef [(FilePath, (FilePath, Maybe Entry))] -- ^ (oldpath, newpath) media
-> Inline
-> IO Inline
-transformInline _ mediaRef (Image lab (src,tit)) = do
- newsrc <- modifyMediaRef mediaRef src
+transformInline opts mediaRef (Image lab (src,tit)) = do
+ newsrc <- modifyMediaRef opts mediaRef src
return $ Image lab (newsrc, tit)
transformInline opts _ (x@(Math _ _))
| WebTeX _ <- writerHTMLMathMethod opts = do
raw <- makeSelfContained opts $ writeHtmlInline opts x
return $ RawInline (Format "html") raw
-transformInline _ mediaRef (RawInline fmt raw)
+transformInline opts mediaRef (RawInline fmt raw)
| fmt == Format "html" = do
let tags = parseTags raw
- tags' <- mapM (transformTag mediaRef) tags
+ tags' <- mapM (transformTag opts mediaRef) tags
return $ RawInline fmt (renderTags' tags')
transformInline _ _ x = return x
@@ -849,11 +914,6 @@ mediaTypeOf x =
Just y | any (`isPrefixOf` y) mediaPrefixes -> Just y
_ -> Nothing
-data IdentState = IdentState{
- chapterNumber :: Int,
- identTable :: [(String,String)]
- } deriving (Read, Show)
-
-- Returns filename for chapter number.
showChapter :: Int -> String
showChapter = printf "ch%03d.xhtml"
@@ -870,38 +930,6 @@ addIdentifiers bs = evalState (mapM go bs) []
return $ Header n (ident',classes,kvs) ils
go x = return x
--- Go through a block list and construct a table
--- correlating the automatically constructed references
--- that would be used in a normal pandoc document with
--- new URLs to be used in the EPUB. For example, what
--- was "header-1" might turn into "ch006.xhtml#header".
-correlateRefs :: Int -> [Block] -> [(String,String)]
-correlateRefs chapterHeaderLevel bs =
- identTable $ execState (mapM_ go bs)
- IdentState{ chapterNumber = 0
- , identTable = [] }
- where go :: Block -> State IdentState ()
- go (Header n (ident,_,_) _) = do
- when (n <= chapterHeaderLevel) $
- modify $ \s -> s{ chapterNumber = chapterNumber s + 1 }
- st <- get
- let chapterid = showChapter (chapterNumber st) ++
- if n <= chapterHeaderLevel
- then ""
- else '#' : ident
- modify $ \s -> s{ identTable = (ident, chapterid) : identTable st }
- go _ = return ()
-
--- Replace internal link references using the table produced
--- by correlateRefs.
-replaceRefs :: [(String,String)] -> [Block] -> [Block]
-replaceRefs refTable = walk replaceOneRef
- where replaceOneRef x@(Link lab ('#':xs,tit)) =
- case lookup xs refTable of
- Just url -> Link lab (url,tit)
- Nothing -> x
- replaceOneRef x = x
-
-- Variant of normalizeDate that allows partial dates: YYYY, YYYY-MM
normalizeDate' :: String -> Maybe String
normalizeDate' xs =
@@ -1198,4 +1226,3 @@ docTitle' meta = fromMaybe [] $ go <$> lookupMeta "title" meta
_ -> []
go (MetaList xs) = concatMap go xs
go _ = []
-
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index 233b8b32b..31fa4bee8 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -85,7 +85,7 @@ writeFB2 opts (Pandoc meta blocks) = flip evalStateT newFB $ do
(imgs,missing) <- liftM imagesToFetch get >>= \s -> liftIO (fetchImages s)
let body' = replaceImagesWithAlt missing body
let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs)
- return $ xml_head ++ (showContent fb2_xml)
+ return $ xml_head ++ (showContent fb2_xml) ++ "\n"
where
xml_head = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
fb2_attrs =
diff --git a/src/Text/Pandoc/Writers/HTML.hs b/src/Text/Pandoc/Writers/HTML.hs
index 1a00c7660..a2778ea97 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -1,7 +1,7 @@
-{-# LANGUAGE OverloadedStrings, CPP, ViewPatterns #-}
+{-# LANGUAGE OverloadedStrings, CPP, ViewPatterns, ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-deprecations #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.HTML
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -46,10 +46,13 @@ import Numeric ( showHex )
import Data.Char ( ord, toLower )
import Data.List ( isPrefixOf, intersperse )
import Data.String ( fromString )
-import Data.Maybe ( catMaybes, fromMaybe )
+import Data.Maybe ( catMaybes, fromMaybe, isJust )
import Control.Monad.State
import Text.Blaze.Html hiding(contents)
+#if MIN_VERSION_blaze_markup(0,6,3)
+#else
import Text.Blaze.Internal(preEscapedString)
+#endif
#if MIN_VERSION_blaze_html(0,5,1)
import qualified Text.Blaze.XHtml5 as H5
#else
@@ -60,7 +63,7 @@ import qualified Text.Blaze.XHtml1.Transitional.Attributes as A
import Text.Blaze.Renderer.String (renderHtml)
import Text.TeXMath
import Text.XML.Light.Output
-import Text.XML.Light (unode, elChildren, add_attr, unqual)
+import Text.XML.Light (unode, elChildren, unqual)
import qualified Text.XML.Light as XML
import System.FilePath (takeExtension)
import Data.Monoid
@@ -73,11 +76,13 @@ data WriterState = WriterState
, stQuotes :: Bool -- ^ <q> tag is used
, stHighlighting :: Bool -- ^ Syntax highlighting is used
, stSecNum :: [Int] -- ^ Number of current section
+ , stElement :: Bool -- ^ Processing an Element
}
defaultWriterState :: WriterState
defaultWriterState = WriterState {stNotes= [], stMath = False, stQuotes = False,
- stHighlighting = False, stSecNum = []}
+ stHighlighting = False, stSecNum = [],
+ stElement = False}
-- Helpers to render HTML with the appropriate function.
@@ -189,6 +194,9 @@ pandocToHtml opts (Pandoc meta blocks) = do
defField "revealjs-url" ("reveal.js" :: String) $
defField "s5-url" ("s5/default" :: String) $
defField "html5" (writerHtml5 opts) $
+ defField "center" (case lookupMeta "center" meta of
+ Just (MetaBool False) -> False
+ _ -> True) $
metadata
return (thebody, context)
@@ -280,7 +288,13 @@ elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elemen
let titleSlide = slide && level < slideLevel
header' <- if title' == [Str "\0"] -- marker for hrule
then return mempty
- else blockToHtml opts (Header level' (id',classes,keyvals) title')
+ else do
+ modify (\st -> st{ stElement = True})
+ res <- blockToHtml opts
+ (Header level' (id',classes,keyvals) title')
+ modify (\st -> st{ stElement = False})
+ return res
+
let isSec (Sec _ _ _ _ _) = True
isSec (Blk _) = False
let isPause (Blk x) = x == Para [Str ".",Space,Str ".",Space,Str "."]
@@ -361,8 +375,8 @@ obfuscateLink opts (renderHtml -> txt) s =
(linkText, altText) =
if txt == drop 7 s' -- autolink
then ("e", name' ++ " at " ++ domain')
- else ("'" ++ txt ++ "'", txt ++ " (" ++ name' ++ " at " ++
- domain' ++ ")")
+ else ("'" ++ obfuscateString txt ++ "'",
+ txt ++ " (" ++ name' ++ " at " ++ domain' ++ ")")
in case meth of
ReferenceObfuscation ->
-- need to use preEscapedString or &'s are escaped to &amp; in URL
@@ -430,24 +444,32 @@ blockToHtml opts (Para [Image txt (s,'f':'i':'g':':':tit)]) = do
then H5.figure $ mconcat
[nl opts, img, capt, nl opts]
else H.div ! A.class_ "figure" $ mconcat
- [nl opts, img, capt, nl opts]
+ [nl opts, img, nl opts, capt, nl opts]
blockToHtml opts (Para lst) = do
contents <- inlineListToHtml opts lst
return $ H.p contents
blockToHtml opts (Div attr@(_,classes,_) bs) = do
- contents <- blockListToHtml opts bs
+ let speakerNotes = "notes" `elem` classes
+ -- we don't want incremental output inside speaker notes, see #1394
+ let opts' = if speakerNotes then opts{ writerIncremental = False } else opts
+ contents <- blockListToHtml opts' bs
let contents' = nl opts >> contents >> nl opts
return $
- if "notes" `elem` classes
- then let opts' = opts{ writerIncremental = False } in
- -- we don't want incremental output inside speaker notes
- case writerSlideVariant opts of
+ if speakerNotes
+ then case writerSlideVariant opts of
RevealJsSlides -> addAttrs opts' attr $ H5.aside $ contents'
+ DZSlides -> (addAttrs opts' attr $ H5.div $ contents')
+ ! (H5.customAttribute "role" "note")
NoSlides -> addAttrs opts' attr $ H.div $ contents'
_ -> mempty
else addAttrs opts attr $ H.div $ contents'
-blockToHtml _ (RawBlock f str)
+blockToHtml opts (RawBlock f str)
| f == Format "html" = return $ preEscapedString str
+ | f == Format "latex" =
+ case writerHTMLMathMethod opts of
+ MathJax _ -> do modify (\st -> st{ stMath = True })
+ return $ toHtml str
+ _ -> return mempty
| otherwise = return mempty
blockToHtml opts (HorizontalRule) = return $ if writerHtml5 opts then H5.hr else H.hr
blockToHtml opts (CodeBlock (id',classes,keyvals) rawCode) = do
@@ -491,7 +513,7 @@ blockToHtml opts (BlockQuote blocks) =
else do
contents <- blockListToHtml opts blocks
return $ H.blockquote $ nl opts >> contents >> nl opts
-blockToHtml opts (Header level (_,classes,_) lst) = do
+blockToHtml opts (Header level attr@(_,classes,_) lst) = do
contents <- inlineListToHtml opts lst
secnum <- liftM stSecNum get
let contents' = if writerNumberSections opts && not (null secnum)
@@ -499,7 +521,9 @@ blockToHtml opts (Header level (_,classes,_) lst) = do
then (H.span ! A.class_ "header-section-number" $ toHtml
$ showSecNum secnum) >> strToHtml " " >> contents
else contents
- return $ case level of
+ inElement <- gets stElement
+ return $ (if inElement then id else addAttrs opts attr)
+ $ case level of
1 -> H.h1 contents'
2 -> H.h2 contents'
3 -> H.h3 contents'
@@ -512,7 +536,9 @@ blockToHtml opts (BulletList lst) = do
return $ unordList opts contents
blockToHtml opts (OrderedList (startnum, numstyle, _) lst) = do
contents <- mapM (blockListToHtml opts) lst
- let numstyle' = camelCaseToHyphenated $ show numstyle
+ let numstyle' = case numstyle of
+ Example -> "decimal"
+ _ -> camelCaseToHyphenated $ show numstyle
let attribs = (if startnum /= 1
then [A.start $ toValue startnum]
else []) ++
@@ -629,7 +655,9 @@ annotateMML e tex = math (unode "semantics" [cs, unode "annotation" (annotAttrs,
[] -> unode "mrow" ()
[x] -> x
xs -> unode "mrow" xs
- math = add_attr (XML.Attr (unqual "xmlns") "http://www.w3.org/1998/Math/MathML") . unode "math"
+ math childs = XML.Element q as [XML.Elem childs] l
+ where
+ (XML.Element q as _ l) = e
annotAttrs = [XML.Attr (unqual "encoding") "application/x-tex"]
@@ -639,7 +667,8 @@ inlineToHtml opts inline =
case inline of
(Str str) -> return $ strToHtml str
(Space) -> return $ strToHtml " "
- (LineBreak) -> return $ if writerHtml5 opts then H5.br else H.br
+ (LineBreak) -> return $ (if writerHtml5 opts then H5.br else H.br)
+ <> strToHtml "\n"
(Span (id',classes,kvs) ils)
-> inlineListToHtml opts ils >>=
return . addAttrs opts attr' . H.span
@@ -687,67 +716,72 @@ inlineToHtml opts inline =
H.q `fmap` inlineListToHtml opts lst
else (\x -> leftQuote >> x >> rightQuote)
`fmap` inlineListToHtml opts lst
- (Math t str) -> modify (\st -> st {stMath = True}) >>
- (case writerHTMLMathMethod opts of
- LaTeXMathML _ ->
- -- putting LaTeXMathML in container with class "LaTeX" prevents
- -- non-math elements on the page from being treated as math by
- -- the javascript
- return $ H.span ! A.class_ "LaTeX" $
- case t of
- InlineMath -> toHtml ("$" ++ str ++ "$")
- DisplayMath -> toHtml ("$$" ++ str ++ "$$")
- JsMath _ -> do
- let m = preEscapedString str
- return $ case t of
- InlineMath -> H.span ! A.class_ "math" $ m
- DisplayMath -> H.div ! A.class_ "math" $ m
- WebTeX url -> do
- let imtag = if writerHtml5 opts then H5.img else H.img
- let m = imtag ! A.style "vertical-align:middle"
- ! A.src (toValue $ url ++ urlEncode str)
- ! A.alt (toValue str)
- ! A.title (toValue str)
- let brtag = if writerHtml5 opts then H5.br else H.br
- return $ case t of
- InlineMath -> m
- DisplayMath -> brtag >> m >> brtag
- GladTeX ->
- return $ case t of
- InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>"
- DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>"
- MathML _ -> do
- let dt = if t == InlineMath
- then DisplayInline
- else DisplayBlock
- let conf = useShortEmptyTags (const False)
- defaultConfigPP
- case writeMathML dt <$> readTeX str of
- Right r -> return $ preEscapedString $
- ppcElement conf (annotateMML r str)
- Left _ -> inlineListToHtml opts
- (texMathToInlines t str) >>=
- return . (H.span ! A.class_ "math")
- MathJax _ -> return $ H.span ! A.class_ "math" $ toHtml $
- case t of
- InlineMath -> "\\(" ++ str ++ "\\)"
- DisplayMath -> "\\[" ++ str ++ "\\]"
- KaTeX _ _ -> return $ H.span ! A.class_ "math" $
- toHtml (case t of
- InlineMath -> str
- DisplayMath -> "\\displaystyle " ++ str)
- PlainMath -> do
- x <- inlineListToHtml opts (texMathToInlines t str)
- let m = H.span ! A.class_ "math" $ x
- let brtag = if writerHtml5 opts then H5.br else H.br
- return $ case t of
- InlineMath -> m
- DisplayMath -> brtag >> m >> brtag )
+ (Math t str) -> do
+ modify (\st -> st {stMath = True})
+ let mathClass = toValue $ ("math " :: String) ++
+ if t == InlineMath then "inline" else "display"
+ case writerHTMLMathMethod opts of
+ LaTeXMathML _ ->
+ -- putting LaTeXMathML in container with class "LaTeX" prevents
+ -- non-math elements on the page from being treated as math by
+ -- the javascript
+ return $ H.span ! A.class_ "LaTeX" $
+ case t of
+ InlineMath -> toHtml ("$" ++ str ++ "$")
+ DisplayMath -> toHtml ("$$" ++ str ++ "$$")
+ JsMath _ -> do
+ let m = preEscapedString str
+ return $ case t of
+ InlineMath -> H.span ! A.class_ mathClass $ m
+ DisplayMath -> H.div ! A.class_ mathClass $ m
+ WebTeX url -> do
+ let imtag = if writerHtml5 opts then H5.img else H.img
+ let m = imtag ! A.style "vertical-align:middle"
+ ! A.src (toValue $ url ++ urlEncode str)
+ ! A.alt (toValue str)
+ ! A.title (toValue str)
+ let brtag = if writerHtml5 opts then H5.br else H.br
+ return $ case t of
+ InlineMath -> m
+ DisplayMath -> brtag >> m >> brtag
+ GladTeX ->
+ return $ case t of
+ InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>"
+ DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>"
+ MathML _ -> do
+ let dt = if t == InlineMath
+ then DisplayInline
+ else DisplayBlock
+ let conf = useShortEmptyTags (const False)
+ defaultConfigPP
+ case writeMathML dt <$> readTeX str of
+ Right r -> return $ preEscapedString $
+ ppcElement conf (annotateMML r str)
+ Left _ -> inlineListToHtml opts
+ (texMathToInlines t str) >>=
+ return . (H.span ! A.class_ mathClass)
+ MathJax _ -> return $ H.span ! A.class_ mathClass $ toHtml $
+ case t of
+ InlineMath -> "\\(" ++ str ++ "\\)"
+ DisplayMath -> "\\[" ++ str ++ "\\]"
+ KaTeX _ _ -> return $ H.span ! A.class_ mathClass $
+ toHtml (case t of
+ InlineMath -> str
+ DisplayMath -> "\\displaystyle " ++ str)
+ PlainMath -> do
+ x <- inlineListToHtml opts (texMathToInlines t str)
+ let m = H.span ! A.class_ mathClass $ x
+ let brtag = if writerHtml5 opts then H5.br else H.br
+ return $ case t of
+ InlineMath -> m
+ DisplayMath -> brtag >> m >> brtag
(RawInline f str)
| f == Format "latex" ->
case writerHTMLMathMethod opts of
LaTeXMathML _ -> do modify (\st -> st {stMath = True})
return $ toHtml str
+ MathJax _ -> do modify (\st -> st {stMath = True})
+ return $ toHtml str
_ -> return mempty
| f == Format "html" -> return $ preEscapedString str
| otherwise -> return mempty
@@ -768,22 +802,15 @@ inlineToHtml opts inline =
then link'
else link' ! A.title (toValue tit)
(Image txt (s,tit)) | treatAsImage s -> do
- let alternate' = stringify txt
let attributes = [A.src $ toValue s] ++
- (if null tit
- then []
- else [A.title $ toValue tit]) ++
- if null txt
- then []
- else [A.alt $ toValue alternate']
+ [A.title $ toValue tit | not $ null tit] ++
+ [A.alt $ toValue $ stringify txt]
let tag = if writerHtml5 opts then H5.img else H.img
return $ foldl (!) tag attributes
-- note: null title included, as in Markdown.pl
(Image _ (s,tit)) -> do
let attributes = [A.src $ toValue s] ++
- (if null tit
- then []
- else [A.title $ toValue tit])
+ [A.title $ toValue tit | not $ null tit]
return $ foldl (!) H5.embed attributes
-- note: null title included, as in Markdown.pl
(Note contents)
@@ -803,7 +830,9 @@ inlineToHtml opts inline =
writerIdentifierPrefix opts ++ "fn" ++ ref)
! A.class_ "footnoteRef"
! prefixedId opts ("fnref" ++ ref)
- $ H.sup
+ $ (if isJust (writerEpubVersion opts)
+ then id
+ else H.sup)
$ toHtml ref
return $ case writerEpubVersion opts of
Just EPUB3 -> link ! customAttribute "epub:type" "noteref"
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index ae20efd4b..08e3e5b63 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE OverloadedStrings, FlexibleContexts #-}
{- |
Module : Text.Pandoc.Writers.ICML
@@ -25,6 +25,7 @@ import Data.List (isPrefixOf, isInfixOf, stripPrefix)
import Data.Text as Text (breakOnAll, pack)
import Data.Monoid (mappend)
import Control.Monad.State
+import Network.URI (isURI)
import qualified Data.Set as Set
type Style = [String]
@@ -70,7 +71,6 @@ linkName = "Link"
-- block element names (appear in InDesign's paragraph styles pane)
paragraphName :: String
codeBlockName :: String
-rawBlockName :: String
blockQuoteName :: String
orderedListName :: String
bulletListName :: String
@@ -93,7 +93,6 @@ subListParName :: String
footnoteName :: String
paragraphName = "Paragraph"
codeBlockName = "CodeBlock"
-rawBlockName = "Rawblock"
blockQuoteName = "Blockquote"
orderedListName = "NumList"
bulletListName = "BulList"
@@ -252,6 +251,13 @@ charStylesToDoc st = vcat $ map makeStyle $ Set.toAscList $ inlineStyles st
else empty
in inTags True "CharacterStyle" ([("Self", "CharacterStyle/"++s), ("Name", s)] ++ attrs') props
+-- | Escape colon characters as %3a
+escapeColons :: String -> String
+escapeColons (x:xs)
+ | x == ':' = "%3a" ++ escapeColons xs
+ | otherwise = x : escapeColons xs
+escapeColons [] = []
+
-- | Convert a list of (identifier, url) pairs to the ICML listing of hyperlinks.
hyperlinksToDoc :: Hyperlink -> Doc
hyperlinksToDoc [] = empty
@@ -260,13 +266,13 @@ hyperlinksToDoc (x:xs) = hyp x $$ hyperlinksToDoc xs
hyp (ident, url) = hdest $$ hlink
where
hdest = selfClosingTag "HyperlinkURLDestination"
- [("Self", "HyperlinkURLDestination/"++url), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")]
+ [("Self", "HyperlinkURLDestination/"++(escapeColons url)), ("Name","link"), ("DestinationURL",url), ("DestinationUniqueKey","1")] -- HyperlinkURLDestination with more than one colon crashes CS6
hlink = inTags True "Hyperlink" [("Self","uf-"++show ident), ("Name",url),
("Source","htss-"++show ident), ("Visible","true"), ("DestinationUniqueKey","1")]
$ inTags True "Properties" []
$ inTags False "BorderColor" [("type","enumeration")] (text "Black")
$$ (inTags False "Destination" [("type","object")]
- $ text $ "HyperlinkURLDestination/"++(escapeStringForXML url))
+ $ text $ "HyperlinkURLDestination/"++(escapeColons (escapeStringForXML url))) -- HyperlinkURLDestination with more than one colon crashes CS6
-- | Convert a list of Pandoc blocks to ICML.
@@ -278,7 +284,9 @@ blockToICML :: WriterOptions -> Style -> Block -> WS Doc
blockToICML opts style (Plain lst) = parStyle opts style lst
blockToICML opts style (Para lst) = parStyle opts (paragraphName:style) lst
blockToICML opts style (CodeBlock _ str) = parStyle opts (codeBlockName:style) $ [Str str]
-blockToICML opts style (RawBlock _ str) = parStyle opts (rawBlockName:style) $ [Str str]
+blockToICML _ _ (RawBlock f str)
+ | f == Format "icml" = return $ text str
+ | otherwise = return empty
blockToICML opts style (BlockQuote blocks) = blocksToICML opts (blockQuoteName:style) blocks
blockToICML opts style (OrderedList attribs lst) = listItemsToICML opts orderedListName style (Just attribs) lst
blockToICML opts style (BulletList lst) = listItemsToICML opts bulletListName style Nothing lst
@@ -399,12 +407,14 @@ inlineToICML opts style (Subscript lst) = inlinesToICML opts (subscriptName:styl
inlineToICML opts style (SmallCaps lst) = inlinesToICML opts (smallCapsName:style) lst
inlineToICML opts style (Quoted SingleQuote lst) = inlinesToICML opts style $ [Str "‘"] ++ lst ++ [Str "’"]
inlineToICML opts style (Quoted DoubleQuote lst) = inlinesToICML opts style $ [Str "“"] ++ lst ++ [Str "”"]
-inlineToICML opts style (Cite _ lst) = footnoteToICML opts style [Para lst]
+inlineToICML opts style (Cite _ lst) = inlinesToICML opts style lst
inlineToICML _ style (Code _ str) = charStyle (codeName:style) $ text $ escapeStringForXML str
inlineToICML _ style Space = charStyle style space
inlineToICML _ style LineBreak = charStyle style $ text lineSeparator
inlineToICML _ style (Math _ str) = charStyle style $ text $ escapeStringForXML str --InDesign doesn't really do math
-inlineToICML _ style (RawInline _ str) = charStyle style $ text $ escapeStringForXML str
+inlineToICML _ _ (RawInline f str)
+ | f == Format "icml" = return $ text str
+ | otherwise = return empty
inlineToICML opts style (Link lst (url, title)) = do
content <- inlinesToICML opts (linkName:style) lst
state $ \st ->
@@ -497,6 +507,7 @@ imageICML _ style _ (linkURI, _) =
hh = show $ imgHeight `div` 2
qw = show $ imgWidth `div` 4
qh = show $ imgHeight `div` 4
+ uriPrefix = if isURI linkURI then "" else "file:"
(stlStr, attrs) = styleToStrAttr style
props = inTags True "Properties" [] $ inTags True "PathGeometry" []
$ inTags True "GeometryPathType" [("PathOpen","false")]
@@ -516,7 +527,7 @@ imageICML _ style _ (linkURI, _) =
$ vcat [
inTags True "Properties" [] $ inTags True "Profile" [("type","string")] $ text "$ID/Embedded"
$$ selfClosingTag "GraphicBounds" [("Left","0"), ("Top","0"), ("Right", hw), ("Bottom", hh)]
- , selfClosingTag "Link" [("Self", "ueb"), ("LinkResourceURI", linkURI)]
+ , selfClosingTag "Link" [("Self", "ueb"), ("LinkResourceURI", uriPrefix++linkURI)]
]
doc = inTags True "CharacterStyleRange" attrs
$ inTags True "Rectangle" [("Self","uec"), ("ItemTransform", "1 0 0 1 "++qw++" -"++qh)]
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index ae2f4e907..506edd182 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables,
PatternGuards #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.LaTeX
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -38,12 +38,13 @@ import Text.Pandoc.Options
import Text.Pandoc.Templates
import Text.Printf ( printf )
import Network.URI ( isURI, unEscapeString )
-import Data.List ( (\\), isSuffixOf, isInfixOf, stripPrefix,
- isPrefixOf, intercalate, intersperse )
+import Data.List ( (\\), isInfixOf, stripPrefix, intercalate, intersperse )
import Data.Char ( toLower, isPunctuation, isAscii, isLetter, isDigit, ord )
import Data.Maybe ( fromMaybe )
+import Data.Aeson.Types ( (.:), parseMaybe, withObject )
import Control.Applicative ((<|>))
import Control.Monad.State
+import qualified Text.Parsec as P
import Text.Pandoc.Pretty
import Text.Pandoc.Slides
import Text.Pandoc.Highlighting (highlight, styleToLaTeX,
@@ -102,25 +103,33 @@ pandocToLaTeX options (Pandoc meta blocks) = do
modify $ \s -> s{ stInternalLinks = query isInternalLink blocks' }
let template = writerTemplate options
-- set stBook depending on documentclass
+ let colwidth = if writerWrapText options
+ then Just $ writerColumns options
+ else Nothing
+ metadata <- metaToJSON options
+ (fmap (render colwidth) . blockListToLaTeX)
+ (fmap (render colwidth) . inlineListToLaTeX)
+ meta
let bookClasses = ["memoir","book","report","scrreprt","scrbook"]
- case lookup "documentclass" (writerVariables options) of
+ let documentClass = case P.parse (do P.skipMany (P.satisfy (/='\\'))
+ P.string "\\documentclass"
+ P.skipMany (P.satisfy (/='{'))
+ P.char '{'
+ P.manyTill P.letter (P.char '}')) "template"
+ template of
+ Right r -> r
+ Left _ -> ""
+ case lookup "documentclass" (writerVariables options) `mplus`
+ parseMaybe (withObject "object" (.: "documentclass")) metadata of
Just x | x `elem` bookClasses -> modify $ \s -> s{stBook = True}
| otherwise -> return ()
- Nothing | any (\x -> "\\documentclass" `isPrefixOf` x &&
- (any (`isSuffixOf` x) bookClasses))
- (lines template) -> modify $ \s -> s{stBook = True}
+ Nothing | documentClass `elem` bookClasses
+ -> modify $ \s -> s{stBook = True}
| otherwise -> return ()
-- check for \usepackage...{csquotes}; if present, we'll use
-- \enquote{...} for smart quotes:
when ("{csquotes}" `isInfixOf` template) $
modify $ \s -> s{stCsquotes = True}
- let colwidth = if writerWrapText options
- then Just $ writerColumns options
- else Nothing
- metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToLaTeX)
- (fmap (render colwidth) . inlineListToLaTeX)
- meta
let (blocks'', lastHeader) = if writerCiteMethod options == Citeproc then
(blocks', [])
else case last blocks' of
@@ -135,6 +144,11 @@ pandocToLaTeX options (Pandoc meta blocks) = do
st <- get
titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
+ let (mainlang, otherlang) =
+ case (reverse . splitBy (==',') . filter (/=' ')) `fmap`
+ getField "lang" metadata of
+ Just (m:os) -> (m, reverse os)
+ _ -> ("", [])
let context = defField "toc" (writerTableOfContents options) $
defField "toc-depth" (show (writerTOCDepth options -
if stBook st
@@ -159,8 +173,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
defField "euro" (stUsesEuro st) $
defField "listings" (writerListings options || stLHS st) $
defField "beamer" (writerBeamer options) $
- defField "mainlang" (maybe "" (reverse . takeWhile (/=',') . reverse)
- (lookup "lang" $ writerVariables options)) $
+ defField "mainlang" mainlang $
+ defField "otherlang" otherlang $
(if stHighlighting st
then defField "highlighting-macros" (styleToLaTeX
$ writerHighlightStyle options )
@@ -206,7 +220,7 @@ stringToLaTeX ctx (x:xs) = do
'€' -> "\\euro{}" ++ rest
'{' -> "\\{" ++ rest
'}' -> "\\}" ++ rest
- '$' -> "\\$" ++ rest
+ '$' | not isUrl -> "\\$" ++ rest
'%' -> "\\%" ++ rest
'&' -> "\\&" ++ rest
'_' | not isUrl -> "\\_" ++ rest
@@ -240,7 +254,7 @@ toLabel z = go `fmap` stringToLaTeX URLString z
where go [] = ""
go (x:xs)
| (isLetter x || isDigit x) && isAscii x = x:go xs
- | elem x "-+=:;." = x:go xs
+ | elem x ("-+=:;." :: String) = x:go xs
| otherwise = "ux" ++ printf "%x" (ord x) ++ go xs
-- | Puts contents into LaTeX command.
@@ -272,10 +286,11 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
let hasCode (Code _ _) = [True]
hasCode _ = []
opts <- gets stOptions
- let fragile = not $ null $ query hasCodeBlock elts ++
+ let fragile = "fragile" `elem` classes ||
+ not (null $ query hasCodeBlock elts ++
if writerListings opts
then query hasCode elts
- else []
+ else [])
let allowframebreaks = "allowframebreaks" `elem` classes
let optionslist = ["fragile" | fragile] ++
["allowframebreaks" | allowframebreaks]
@@ -311,7 +326,8 @@ blockToLaTeX (Div (identifier,classes,_) bs) = do
ref <- toLabel identifier
let linkAnchor = if null identifier
then empty
- else "\\hyperdef{}" <> braces (text ref) <> "{}"
+ else "\\hyperdef{}" <> braces (text ref) <>
+ braces ("\\label" <> braces (text ref))
contents <- blockListToLaTeX bs
if beamer && "notes" `elem` classes -- speaker notes
then return $ "\\note" <> braces contents
@@ -414,7 +430,7 @@ blockToLaTeX (BulletList lst) = do
let inc = if incremental then "[<+->]" else ""
items <- mapM listItemToLaTeX lst
let spacing = if isTightList lst
- then text "\\itemsep1pt\\parskip0pt\\parsep0pt"
+ then text "\\tightlist"
else empty
return $ text ("\\begin{itemize}" ++ inc) $$ spacing $$ vcat items $$
"\\end{itemize}"
@@ -449,7 +465,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
else "\\setcounter" <> braces enum <>
braces (text $ show $ start - 1)
let spacing = if isTightList lst
- then text "\\itemsep1pt\\parskip0pt\\parsep0pt"
+ then text "\\tightlist"
else empty
return $ text ("\\begin{enumerate}" ++ inc)
$$ stylecommand
@@ -463,7 +479,7 @@ blockToLaTeX (DefinitionList lst) = do
let inc = if incremental then "[<+->]" else ""
items <- mapM defListItemToLaTeX lst
let spacing = if all isTightList (map snd lst)
- then text "\\itemsep1pt\\parskip0pt\\parsep0pt"
+ then text "\\tightlist"
else empty
return $ text ("\\begin{description}" ++ inc) $$ spacing $$ vcat items $$
"\\end{description}"
@@ -545,10 +561,16 @@ fixLineBreaks' ils = case splitBy (== LineBreak) ils of
where tohbox ys = RawInline "tex" "\\hbox{\\strut " : ys ++
[RawInline "tex" "}"]
+-- We also change display math to inline math, since display
+-- math breaks in simple tables.
+displayMathToInline :: Inline -> Inline
+displayMathToInline (Math DisplayMath x) = Math InlineMath x
+displayMathToInline x = x
+
tableCellToLaTeX :: Bool -> (Double, Alignment, [Block])
-> State WriterState Doc
tableCellToLaTeX _ (0, _, blocks) =
- blockListToLaTeX $ walk fixLineBreaks blocks
+ blockListToLaTeX $ walk fixLineBreaks $ walk displayMathToInline blocks
tableCellToLaTeX header (width, align, blocks) = do
modify $ \st -> st{ stInMinipage = True, stNotes = [] }
cellContents <- blockListToLaTeX blocks
@@ -613,6 +635,7 @@ sectionHeader :: Bool -- True for unnumbered
sectionHeader unnumbered ref level lst = do
txt <- inlineListToLaTeX lst
lab <- text `fmap` toLabel ref
+ plain <- stringToLaTeX TextString $ foldl (++) "" $ map stringify lst
let noNote (Note _) = Str ""
noNote x = x
let lstNoNotes = walk noNote lst
@@ -625,7 +648,12 @@ sectionHeader unnumbered ref level lst = do
then return empty
else do
return $ brackets txtNoNotes
- let stuffing = star <> optional <> braces txt
+ let contents = if render Nothing txt == plain
+ then braces txt
+ else braces (text "\\texorpdfstring"
+ <> braces txt
+ <> braces (text plain))
+ let stuffing = star <> optional <> contents
book <- gets stBook
opts <- gets stOptions
let level' = if book || writerChapters opts then level - 1 else level
@@ -669,7 +697,7 @@ sectionHeader unnumbered ref level lst = do
inlineListToLaTeX :: [Inline] -- ^ Inlines to convert
-> State WriterState Doc
inlineListToLaTeX lst =
- mapM inlineToLaTeX (fixLineInitialSpaces lst)
+ mapM inlineToLaTeX (fixBreaks $ fixLineInitialSpaces lst)
>>= return . hcat
-- nonbreaking spaces (~) in LaTeX don't work after line breaks,
-- so we turn nbsps after hard breaks to \hspace commands.
@@ -681,6 +709,14 @@ inlineListToLaTeX lst =
fixNbsps s = let (ys,zs) = span (=='\160') s
in replicate (length ys) hspace ++ [Str zs]
hspace = RawInline "latex" "\\hspace*{0.333em}"
+ -- linebreaks after blank lines cause problems:
+ fixBreaks [] = []
+ fixBreaks ys@(LineBreak : LineBreak : _) =
+ case span (== LineBreak) ys of
+ (lbs, rest) -> RawInline "latex"
+ ("\\\\[" ++ show (length lbs) ++
+ "\\baselineskip]") : fixBreaks rest
+ fixBreaks (y:ys) = y : fixBreaks ys
isQuoted :: Inline -> Bool
isQuoted (Quoted _ _) = True
@@ -696,7 +732,8 @@ inlineToLaTeX (Span (id',classes,_) ils) = do
ref <- toLabel id'
let linkAnchor = if null id'
then empty
- else "\\hyperdef{}" <> braces (text ref) <> "{}"
+ else "\\hyperdef{}" <> braces (text ref) <>
+ braces ("\\label" <> braces (text ref))
fmap (linkAnchor <>)
((if noEmph then inCmd "textup" else id) .
(if noStrong then inCmd "textnormal" else id) .
@@ -730,10 +767,11 @@ inlineToLaTeX (Cite cits lst) = do
inlineToLaTeX (Code (_,classes,_) str) = do
opts <- gets stOptions
+ inHeading <- gets stInHeading
case () of
- _ | writerListings opts -> listingsCode
+ _ | writerListings opts && not inHeading -> listingsCode
| writerHighlight opts && not (null classes) -> highlightCode
- | otherwise -> rawCode
+ | otherwise -> rawCode
where listingsCode = do
inNote <- gets stInNote
when inNote $ modify $ \s -> s{ stVerbInNote = True }
@@ -746,8 +784,10 @@ inlineToLaTeX (Code (_,classes,_) str) = do
Nothing -> rawCode
Just h -> modify (\st -> st{ stHighlighting = True }) >>
return (text h)
- rawCode = liftM (text . (\s -> "\\texttt{" ++ s ++ "}"))
+ rawCode = liftM (text . (\s -> "\\texttt{" ++ escapeSpaces s ++ "}"))
$ stringToLaTeX CodeString str
+ where
+ escapeSpaces = concatMap (\c -> if c == ' ' then "\\ " else [c])
inlineToLaTeX (Quoted qt lst) = do
contents <- inlineListToLaTeX lst
csquotes <- liftM stCsquotes get
@@ -780,7 +820,7 @@ inlineToLaTeX (RawInline f str)
| f == Format "latex" || f == Format "tex"
= return $ text str
| otherwise = return empty
-inlineToLaTeX (LineBreak) = return "\\\\"
+inlineToLaTeX (LineBreak) = return $ "\\\\" <> cr
inlineToLaTeX Space = return space
inlineToLaTeX (Link txt ('#':ident, _)) = do
contents <- inlineListToLaTeX txt
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index 6b2c4c200..f91367eb9 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2007-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Man
- Copyright : Copyright (C) 2007-2014 John MacFarlane
+ Copyright : Copyright (C) 2007-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index f06f1d6cc..804f4101d 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings, TupleSections, ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Markdown
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -44,7 +44,6 @@ import Data.Char ( isSpace, isPunctuation )
import Data.Ord ( comparing )
import Text.Pandoc.Pretty
import Control.Monad.State
-import qualified Data.Set as Set
import Text.Pandoc.Writers.HTML (writeHtmlString)
import Text.Pandoc.Readers.TeXMath (texMathToInlines)
import Text.HTML.TagSoup (parseTags, isTagText, Tag(..))
@@ -57,12 +56,15 @@ import qualified Data.Text as T
type Notes = [[Block]]
type Refs = [([Inline], Target)]
-data WriterState = WriterState { stNotes :: Notes
- , stRefs :: Refs
- , stIds :: [String]
- , stPlain :: Bool }
+data WriterState = WriterState { stNotes :: Notes
+ , stRefs :: Refs
+ , stRefShortcutable :: Bool
+ , stInList :: Bool
+ , stIds :: [String]
+ , stPlain :: Bool }
instance Default WriterState
- where def = WriterState{ stNotes = [], stRefs = [], stIds = [], stPlain = False }
+ where def = WriterState{ stNotes = [], stRefs = [], stRefShortcutable = True,
+ stInList = False, stIds = [], stPlain = False }
-- | Convert Pandoc to Markdown.
writeMarkdown :: WriterOptions -> Pandoc -> String
@@ -76,17 +78,7 @@ writeMarkdown opts document =
-- pictures, or inline formatting).
writePlain :: WriterOptions -> Pandoc -> String
writePlain opts document =
- evalState (pandocToMarkdown opts{
- writerExtensions = Set.delete Ext_escaped_line_breaks $
- Set.delete Ext_pipe_tables $
- Set.delete Ext_raw_html $
- Set.delete Ext_markdown_in_html_blocks $
- Set.delete Ext_raw_tex $
- Set.delete Ext_footnotes $
- Set.delete Ext_tex_math_dollars $
- Set.delete Ext_citations $
- writerExtensions opts }
- document) def{ stPlain = True }
+ evalState (pandocToMarkdown opts document) def{ stPlain = True }
pandocTitleBlock :: Doc -> [Doc] -> Doc -> Doc
pandocTitleBlock tit auths dat =
@@ -243,7 +235,8 @@ noteToMarkdown opts num blocks = do
-- | Escape special characters for Markdown.
escapeString :: WriterOptions -> String -> String
escapeString opts = escapeStringUsing markdownEscapes
- where markdownEscapes = backslashEscapes specialChars
+ where markdownEscapes = ('<', "&lt;") : ('>', "&gt;") :
+ backslashEscapes specialChars
specialChars =
(if isEnabled Ext_superscript opts
then ('^':)
@@ -254,7 +247,7 @@ escapeString opts = escapeStringUsing markdownEscapes
(if isEnabled Ext_tex_math_dollars opts
then ('$':)
else id) $
- "\\`*_<>#"
+ "\\`*_[]#"
-- | Construct table of contents from list of header blocks.
tableOfContents :: WriterOptions -> [Block] -> Doc
@@ -323,9 +316,9 @@ blockToMarkdown opts (Plain inlines) = do
then Just $ writerColumns opts
else Nothing
let rendered = render colwidth contents
- let escapeDelimiter (x:xs) | x `elem` ".()" = '\\':x:xs
- | otherwise = x : escapeDelimiter xs
- escapeDelimiter [] = []
+ let escapeDelimiter (x:xs) | x `elem` (".()" :: String) = '\\':x:xs
+ | otherwise = x : escapeDelimiter xs
+ escapeDelimiter [] = []
let contents' = if isEnabled Ext_all_symbols_escapable opts &&
not (stPlain st) && beginsWithOrderedListMarker rendered
then text $ escapeDelimiter rendered
@@ -453,7 +446,7 @@ blockToMarkdown opts t@(Table caption aligns widths headers rows) = do
$ Pandoc nullMeta [t]
return $ nst $ tbl $$ blankline $$ caption'' $$ blankline
blockToMarkdown opts (BulletList items) = do
- contents <- mapM (bulletListItemToMarkdown opts) items
+ contents <- inList $ mapM (bulletListItemToMarkdown opts) items
return $ cat contents <> blankline
blockToMarkdown opts (OrderedList (start,sty,delim) items) = do
let start' = if isEnabled Ext_startnum opts then start else 1
@@ -464,13 +457,22 @@ blockToMarkdown opts (OrderedList (start,sty,delim) items) = do
let markers' = map (\m -> if length m < 3
then m ++ replicate (3 - length m) ' '
else m) markers
- contents <- mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
+ contents <- inList $
+ mapM (\(item, num) -> orderedListItemToMarkdown opts item num) $
zip markers' items
return $ cat contents <> blankline
blockToMarkdown opts (DefinitionList items) = do
- contents <- mapM (definitionListItemToMarkdown opts) items
+ contents <- inList $ mapM (definitionListItemToMarkdown opts) items
return $ cat contents <> blankline
+inList :: State WriterState a -> State WriterState a
+inList p = do
+ oldInList <- gets stInList
+ modify $ \st -> st{ stInList = True }
+ res <- p
+ modify $ \st -> st{ stInList = oldInList }
+ return res
+
addMarkdownAttribute :: String -> String
addMarkdownAttribute s =
case span isTagText $ reverse $ parseTags s of
@@ -497,7 +499,12 @@ pipeTable headless aligns rawHeaders rawRows = do
AlignCenter -> ':':replicate w '-' ++ ":"
AlignRight -> replicate (w + 1) '-' ++ ":"
AlignDefault -> replicate (w + 2) '-'
- let header = if headless then empty else torow rawHeaders
+ -- note: pipe tables can't completely lack a
+ -- header; for a headerless table, we need a header of empty cells.
+ -- see jgm/pandoc#1996.
+ let header = if headless
+ then torow (replicate (length aligns) empty)
+ else torow rawHeaders
let border = nowrap $ text "|" <> hcat (intersperse (text "|") $
map toborder $ zip aligns widths) <> text "|"
let body = vcat $ map torow rawRows
@@ -677,12 +684,53 @@ getReference label (src, tit) = do
-- | Convert list of Pandoc inline elements to markdown.
inlineListToMarkdown :: WriterOptions -> [Inline] -> State WriterState Doc
-inlineListToMarkdown opts lst =
- mapM (inlineToMarkdown opts) (avoidBadWraps lst) >>= return . cat
- where avoidBadWraps [] = []
- avoidBadWraps (Space:Str (c:cs):xs)
- | c `elem` "-*+>" = Str (' ':c:cs) : avoidBadWraps xs
- avoidBadWraps (x:xs) = x : avoidBadWraps xs
+inlineListToMarkdown opts lst = do
+ inlist <- gets stInList
+ go (if inlist then avoidBadWrapsInList lst else lst)
+ where go [] = return empty
+ go (i:is) = case i of
+ (Link _ _) -> case is of
+ -- If a link is followed by another link or '[' we don't shortcut
+ (Link _ _):_ -> unshortcutable
+ Space:(Link _ _):_ -> unshortcutable
+ Space:(Str('[':_)):_ -> unshortcutable
+ Space:(RawInline _ ('[':_)):_ -> unshortcutable
+ Space:(Cite _ _):_ -> unshortcutable
+ (Cite _ _):_ -> unshortcutable
+ Str ('[':_):_ -> unshortcutable
+ (RawInline _ ('[':_)):_ -> unshortcutable
+ (RawInline _ (' ':'[':_)):_ -> unshortcutable
+ _ -> shortcutable
+ _ -> shortcutable
+ where shortcutable = liftM2 (<>) (inlineToMarkdown opts i) (go is)
+ unshortcutable = do
+ iMark <- withState (\s -> s { stRefShortcutable = False })
+ (inlineToMarkdown opts i)
+ modify (\s -> s {stRefShortcutable = True })
+ fmap (iMark <>) (go is)
+
+avoidBadWrapsInList :: [Inline] -> [Inline]
+avoidBadWrapsInList [] = []
+avoidBadWrapsInList (Space:Str ('>':cs):xs) =
+ Str (' ':'>':cs) : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str [c]:[])
+ | c `elem` ['-','*','+'] = Str [' ', c] : []
+avoidBadWrapsInList (Space:Str [c]:Space:xs)
+ | c `elem` ['-','*','+'] = Str [' ', c] : Space : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str cs:Space:xs)
+ | isOrderedListMarker cs = Str (' ':cs) : Space : avoidBadWrapsInList xs
+avoidBadWrapsInList (Space:Str cs:[])
+ | isOrderedListMarker cs = Str (' ':cs) : []
+avoidBadWrapsInList (x:xs) = x : avoidBadWrapsInList xs
+
+isOrderedListMarker :: String -> Bool
+isOrderedListMarker xs = (last xs `elem` ['.',')']) &&
+ isRight (runParserT (anyOrderedListMarker >> eof)
+ defaultParserState "" xs)
+
+isRight :: Either a b -> Bool
+isRight (Right _) = True
+isRight (Left _) = False
escapeSpaces :: Inline -> Inline
escapeSpaces (Str s) = Str $ substitute " " "\\ " s
@@ -692,8 +740,10 @@ escapeSpaces x = x
-- | Convert Pandoc inline element to markdown.
inlineToMarkdown :: WriterOptions -> Inline -> State WriterState Doc
inlineToMarkdown opts (Span attrs ils) = do
+ plain <- gets stPlain
contents <- inlineListToMarkdown opts ils
- return $ if isEnabled Ext_raw_html opts
+ return $ if not plain &&
+ (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
then tagWithAttrs "span" attrs <> contents <> text "</span>"
else contents
inlineToMarkdown opts (Emph lst) = do
@@ -713,26 +763,33 @@ inlineToMarkdown opts (Strikeout lst) = do
contents <- inlineListToMarkdown opts lst
return $ if isEnabled Ext_strikeout opts
then "~~" <> contents <> "~~"
- else "<s>" <> contents <> "</s>"
+ else if isEnabled Ext_raw_html opts
+ then "<s>" <> contents <> "</s>"
+ else contents
inlineToMarkdown opts (Superscript lst) = do
contents <- inlineListToMarkdown opts $ walk escapeSpaces lst
return $ if isEnabled Ext_superscript opts
then "^" <> contents <> "^"
- else "<sup>" <> contents <> "</sup>"
+ else if isEnabled Ext_raw_html opts
+ then "<sup>" <> contents <> "</sup>"
+ else contents
inlineToMarkdown opts (Subscript lst) = do
contents <- inlineListToMarkdown opts $ walk escapeSpaces lst
return $ if isEnabled Ext_subscript opts
then "~" <> contents <> "~"
- else "<sub>" <> contents <> "</sub>"
+ else if isEnabled Ext_raw_html opts
+ then "<sub>" <> contents <> "</sub>"
+ else contents
inlineToMarkdown opts (SmallCaps lst) = do
plain <- gets stPlain
- if plain
- then inlineListToMarkdown opts $ capitalize lst
- else do
+ if not plain &&
+ (isEnabled Ext_raw_html opts || isEnabled Ext_native_spans opts)
+ then do
contents <- inlineListToMarkdown opts lst
return $ tagWithAttrs "span"
- ("",[],[("style","font-variant:small-caps;")])
+ ("",[],[("style","font-variant:small-caps;")])
<> contents <> text "</span>"
+ else inlineListToMarkdown opts $ capitalize lst
inlineToMarkdown opts (Quoted SingleQuote lst) = do
contents <- inlineListToMarkdown opts lst
return $ "‘" <> contents <> "’"
@@ -821,8 +878,8 @@ inlineToMarkdown opts (Cite (c:cs) lst)
sdoc <- inlineListToMarkdown opts sinlines
let k' = text (modekey m ++ "@" ++ k)
r = case sinlines of
- Str (y:_):_ | y `elem` ",;]@" -> k' <> sdoc
- _ -> k' <+> sdoc
+ Str (y:_):_ | y `elem` (",;]@" :: String) -> k' <> sdoc
+ _ -> k' <+> sdoc
return $ pdoc <+> r
modekey SuppressAuthor = "-"
modekey _ = ""
@@ -838,6 +895,9 @@ inlineToMarkdown opts (Link txt (src, tit)) = do
[Str s] | escapeURI s == srcSuffix -> True
_ -> False
let useRefLinks = writerReferenceLinks opts && not useAuto
+ shortcutable <- gets stRefShortcutable
+ let useShortcutRefLinks = shortcutable &&
+ isEnabled Ext_shortcut_reference_links opts
ref <- if useRefLinks then getReference txt (src, tit) else return []
reftext <- inlineListToMarkdown opts ref
return $ if useAuto
@@ -847,7 +907,9 @@ inlineToMarkdown opts (Link txt (src, tit)) = do
else if useRefLinks
then let first = "[" <> linktext <> "]"
second = if txt == ref
- then "[]"
+ then if useShortcutRefLinks
+ then ""
+ else "[]"
else "[" <> reftext <> "]"
in first <> second
else if plain
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index 3f392a5d0..2b7c47e24 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.MediaWiki
- Copyright : Copyright (C) 2008-2014 John MacFarlane
+ Copyright : Copyright (C) 2008-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -107,7 +107,7 @@ blockToMediaWiki (Para [Image txt (src,'f':'i':'g':':':tit)]) = do
let opt = if null txt
then ""
else "|alt=" ++ if null tit then capt else tit ++ capt
- return $ "[[Image:" ++ src ++ "|frame|none" ++ opt ++ "]]\n"
+ return $ "[[File:" ++ src ++ "|frame|none" ++ opt ++ "]]\n"
blockToMediaWiki (Para inlines) = do
tags <- asks useTags
@@ -375,14 +375,14 @@ inlineToMediaWiki (RawInline f str)
| f == Format "html" = return str
| otherwise = return ""
-inlineToMediaWiki (LineBreak) = return "<br />"
+inlineToMediaWiki (LineBreak) = return "<br />\n"
inlineToMediaWiki Space = return " "
inlineToMediaWiki (Link txt (src, _)) = do
label <- inlineListToMediaWiki txt
case txt of
- [Str s] | escapeURI s == src -> return src
+ [Str s] | isURI src && escapeURI s == src -> return src
_ -> return $ if isURI src
then "[" ++ src ++ " " ++ label ++ "]"
else "[[" ++ src' ++ "|" ++ label ++ "]]"
@@ -397,7 +397,7 @@ inlineToMediaWiki (Image alt (source, tit)) = do
then ""
else '|' : alt'
else '|' : tit
- return $ "[[Image:" ++ source ++ txt ++ "]]"
+ return $ "[[File:" ++ source ++ txt ++ "]]"
inlineToMediaWiki (Note contents) = do
contents' <- blockListToMediaWiki contents
diff --git a/src/Text/Pandoc/Writers/Native.hs b/src/Text/Pandoc/Writers/Native.hs
index cb821e40b..f342dc4f5 100644
--- a/src/Text/Pandoc/Writers/Native.hs
+++ b/src/Text/Pandoc/Writers/Native.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Native
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
index 03f8e8ba4..b87a391fb 100644
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2008-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.ODT
- Copyright : Copyright (C) 2008-2014 John MacFarlane
+ Copyright : Copyright (C) 2008-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -39,9 +39,10 @@ import Text.Pandoc.UTF8 ( fromStringLazy )
import Codec.Archive.Zip
import Control.Applicative ((<$>))
import Text.Pandoc.Options ( WriterOptions(..) )
-import Text.Pandoc.Shared ( stringify, readDataFile, fetchItem', warn )
+import Text.Pandoc.Shared ( stringify, fetchItem', warn,
+ getDefaultReferenceODT )
import Text.Pandoc.ImageSize ( imageSize, sizeInPoints )
-import Text.Pandoc.MIME ( getMimeType )
+import Text.Pandoc.MIME ( getMimeType, extensionFromMimeType )
import Text.Pandoc.Definition
import Text.Pandoc.Walk
import Text.Pandoc.Writers.Shared ( fixDisplayMath )
@@ -51,7 +52,7 @@ import Text.Pandoc.XML
import Text.Pandoc.Pretty
import qualified Control.Exception as E
import Data.Time.Clock.POSIX ( getPOSIXTime )
-import System.FilePath ( takeExtension, takeDirectory )
+import System.FilePath ( takeExtension, takeDirectory, (<.>))
-- | Produce an ODT file from a Pandoc document.
writeODT :: WriterOptions -- ^ Writer options
@@ -60,11 +61,10 @@ writeODT :: WriterOptions -- ^ Writer options
writeODT opts doc@(Pandoc meta _) = do
let datadir = writerUserDataDir opts
let title = docTitle meta
- refArchive <- liftM toArchive $
+ refArchive <-
case writerReferenceODT opts of
- Just f -> B.readFile f
- Nothing -> (B.fromChunks . (:[])) `fmap`
- readDataFile datadir "reference.odt"
+ Just f -> liftM toArchive $ B.readFile f
+ Nothing -> getDefaultReferenceODT datadir
-- handle formulas and pictures
picEntriesRef <- newIORef ([] :: [Entry])
doc' <- walkM (transformPicMath opts picEntriesRef) $ walk fixDisplayMath doc
@@ -127,23 +127,31 @@ writeODT opts doc@(Pandoc meta _) = do
return $ fromArchive archive''
transformPicMath :: WriterOptions -> IORef [Entry] -> Inline -> IO Inline
-transformPicMath opts entriesRef (Image lab (src,_)) = do
+transformPicMath opts entriesRef (Image lab (src,t)) = do
res <- fetchItem' (writerMediaBag opts) (writerSourceURL opts) src
case res of
Left (_ :: E.SomeException) -> do
warn $ "Could not find image `" ++ src ++ "', skipping..."
return $ Emph lab
- Right (img, _) -> do
- let size = imageSize img
- let (w,h) = fromMaybe (0,0) $ sizeInPoints `fmap` size
+ Right (img, mbMimeType) -> do
+ (w,h) <- case imageSize img of
+ Right size -> return $ sizeInPoints size
+ Left msg -> do
+ warn $ "Could not determine image size in `" ++
+ src ++ "': " ++ msg
+ return (0,0)
let tit' = show w ++ "x" ++ show h
entries <- readIORef entriesRef
- let newsrc = "Pictures/" ++ show (length entries) ++ takeExtension src
+ let extension = fromMaybe (takeExtension $ takeWhile (/='?') src)
+ (mbMimeType >>= extensionFromMimeType)
+ let newsrc = "Pictures/" ++ show (length entries) <.> extension
let toLazy = B.fromChunks . (:[])
epochtime <- floor `fmap` getPOSIXTime
let entry = toEntry newsrc epochtime $ toLazy img
modifyIORef entriesRef (entry:)
- return $ Image lab (newsrc, tit')
+ let fig | "fig:" `isPrefixOf` t = "fig:"
+ | otherwise = ""
+ return $ Image lab (newsrc, fig++tit')
transformPicMath _ entriesRef (Math t math) = do
entries <- readIORef entriesRef
let dt = if t == InlineMath then DisplayInline else DisplayBlock
diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs
index dd359f3f5..c7563d751 100644
--- a/src/Text/Pandoc/Writers/OPML.hs
+++ b/src/Text/Pandoc/Writers/OPML.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.OPML
- Copyright : Copyright (C) 2013-2014 John MacFarlane
+ Copyright : Copyright (C) 2013-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -38,7 +38,7 @@ import Text.Pandoc.Writers.HTML (writeHtmlString)
import Text.Pandoc.Writers.Markdown (writeMarkdown)
import Text.Pandoc.Pretty
import Data.Time
-import System.Locale (defaultTimeLocale)
+import Text.Pandoc.Compat.Locale (defaultTimeLocale)
import qualified Text.Pandoc.Builder as B
-- | Convert Pandoc document to string in OPML format.
@@ -87,4 +87,3 @@ elementToOPML opts (Sec _ _num _ title elements) =
| not (null blocks)]
in inTags True "outline" attrs $
vcat (map (elementToOPML opts) rest)
-
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 773d142f4..83e17c943 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -1,6 +1,6 @@
-{-# LANGUAGE PatternGuards, OverloadedStrings #-}
+{-# LANGUAGE PatternGuards, OverloadedStrings, FlexibleContexts #-}
{-
-Copyright (C) 2008-2014 Andrea Rossato <andrea.rossato@ing.unitn.it>
+Copyright (C) 2008-2015 Andrea Rossato <andrea.rossato@ing.unitn.it>
and John MacFarlane.
This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.OpenDocument
- Copyright : Copyright (C) 2008-2014 Andrea Rossato and John MacFarlane
+ Copyright : Copyright (C) 2008-2015 Andrea Rossato and John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Andrea Rossato <andrea.rossato@ing.unitn.it>
@@ -288,6 +288,8 @@ blockToOpenDocument o bs
| Plain b <- bs = if null b
then return empty
else inParagraphTags =<< inlinesToOpenDocument o b
+ | Para [Image c (s,'f':'i':'g':':':t)] <- bs
+ = figure c s t
| Para b <- bs = if null b
then return empty
else inParagraphTags =<< inlinesToOpenDocument o b
@@ -334,7 +336,7 @@ blockToOpenDocument o bs
mapM_ addParaStyle . newPara $ paraHStyles ++ paraStyles
captionDoc <- if null c
then return empty
- else withParagraphStyle o "Caption" [Para c]
+ else withParagraphStyle o "TableCaption" [Para c]
th <- if all null h
then return empty
else colHeadsToOpenDocument o name (map fst paraHStyles) h
@@ -342,6 +344,12 @@ blockToOpenDocument o bs
return $ inTags True "table:table" [ ("table:name" , name)
, ("table:style-name", name)
] (vcat columns $$ th $$ vcat tr) $$ captionDoc
+ figure caption source title | null caption =
+ withParagraphStyle o "Figure" [Para [Image caption (source,title)]]
+ | otherwise = do
+ imageDoc <- withParagraphStyle o "FigureWithCaption" [Para [Image caption (source,title)]]
+ captionDoc <- withParagraphStyle o "FigureCaption" [Para caption]
+ return $ imageDoc $$ captionDoc
colHeadsToOpenDocument :: WriterOptions -> String -> [String] -> [[Block]] -> State WriterState Doc
colHeadsToOpenDocument o tn ns hs =
@@ -553,4 +561,3 @@ textStyleAttr s
,("style:font-name-asian" ,"Courier New")
,("style:font-name-complex" ,"Courier New")]
| otherwise = []
-
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index 414883b29..90b396cae 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2010-2014 Puneeth Chaganti <punchagan@gmail.com>
+Copyright (C) 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
and John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Org
- Copyright : Copyright (C) 2010-2014 Puneeth Chaganti and John MacFarlane
+ Copyright : Copyright (C) 2010-2015 Puneeth Chaganti and John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Puneeth Chaganti <punchagan@gmail.com>
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index a96670c96..151d3c2ae 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.RST
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -48,11 +48,13 @@ import Data.Char (isSpace, toLower)
type Refs = [([Inline], Target)]
data WriterState =
- WriterState { stNotes :: [[Block]]
- , stLinks :: Refs
- , stImages :: [([Inline], (String, String, Maybe String))]
- , stHasMath :: Bool
- , stOptions :: WriterOptions
+ WriterState { stNotes :: [[Block]]
+ , stLinks :: Refs
+ , stImages :: [([Inline], (String, String, Maybe String))]
+ , stHasMath :: Bool
+ , stHasRawTeX :: Bool
+ , stOptions :: WriterOptions
+ , stTopLevel :: Bool
}
-- | Convert Pandoc to RST.
@@ -60,7 +62,8 @@ writeRST :: WriterOptions -> Pandoc -> String
writeRST opts document =
let st = WriterState { stNotes = [], stLinks = [],
stImages = [], stHasMath = False,
- stOptions = opts }
+ stHasRawTeX = False, stOptions = opts,
+ stTopLevel = True}
in evalState (pandocToRST document) st
-- | Return RST representation of document.
@@ -78,23 +81,32 @@ pandocToRST (Pandoc meta blocks) = do
(fmap (render colwidth) . blockListToRST)
(fmap (trimr . render colwidth) . inlineListToRST)
$ deleteMeta "title" $ deleteMeta "subtitle" meta
- body <- blockListToRST blocks
+ body <- blockListToRST' True $ normalizeHeadings 1 blocks
notes <- liftM (reverse . stNotes) get >>= notesToRST
-- note that the notes may contain refs, so we do them first
refs <- liftM (reverse . stLinks) get >>= refsToRST
pics <- liftM (reverse . stImages) get >>= pictRefsToRST
hasMath <- liftM stHasMath get
+ rawTeX <- liftM stHasRawTeX get
let main = render colwidth $ foldl ($+$) empty $ [body, notes, refs, pics]
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts)
- $ defField "toc-depth" (writerTOCDepth opts)
+ $ defField "toc-depth" (show $ writerTOCDepth opts)
$ defField "math" hasMath
$ defField "title" (render Nothing title :: String)
$ defField "math" hasMath
+ $ defField "rawtex" rawTeX
$ metadata
if writerStandalone opts
then return $ renderTemplate' (writerTemplate opts) context
else return main
+ where
+ normalizeHeadings lev (Header l a i:bs) = Header lev a i:normalizeHeadings (lev+1) cont ++ normalizeHeadings lev bs'
+ where (cont,bs') = break (headerLtEq l) bs
+ headerLtEq level (Header l' _ _) = l' <= level
+ headerLtEq _ _ = False
+ normalizeHeadings lev (b:bs) = b:normalizeHeadings lev bs
+ normalizeHeadings _ [] = []
-- | Return RST representation of reference key table.
refsToRST :: Refs -> State WriterState Doc
@@ -105,7 +117,7 @@ keyToRST :: ([Inline], (String, String))
-> State WriterState Doc
keyToRST (label, (src, _)) = do
label' <- inlineListToRST label
- let label'' = if ':' `elem` (render Nothing label')
+ let label'' = if ':' `elem` ((render Nothing label') :: String)
then char '`' <> label' <> char '`'
else label'
return $ nowrap $ ".. _" <> label'' <> ": " <> text src
@@ -173,7 +185,7 @@ blockToRST (Para [Image txt (src,'f':'i':'g':':':tit)]) = do
capt <- inlineListToRST txt
let fig = "figure:: " <> text src
let alt = ":alt: " <> if null tit then capt else text tit
- return $ hang 3 ".. " $ fig $$ alt $+$ capt $$ blankline
+ return $ hang 3 ".. " (fig $$ alt $+$ capt) $$ blankline
blockToRST (Para inlines)
| LineBreak `elem` inlines = do -- use line block if LineBreaks
lns <- mapM inlineListToRST $ splitBy (==LineBreak) inlines
@@ -188,11 +200,21 @@ blockToRST (RawBlock f@(Format f') str)
(nest 3 $ text str) $$ blankline
blockToRST HorizontalRule =
return $ blankline $$ "--------------" $$ blankline
-blockToRST (Header level _ inlines) = do
+blockToRST (Header level (name,classes,_) inlines) = do
contents <- inlineListToRST inlines
- let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
- let border = text $ replicate (offset contents) headerChar
- return $ nowrap $ contents $$ border $$ blankline
+ isTopLevel <- gets stTopLevel
+ if isTopLevel
+ then do
+ let headerChar = if level > 5 then ' ' else "=-~^'" !! (level - 1)
+ let border = text $ replicate (offset contents) headerChar
+ return $ nowrap $ contents $$ border $$ blankline
+ else do
+ let rub = "rubric:: " <> contents
+ let name' | null name = empty
+ | otherwise = ":name: " <> text name
+ let cls | null classes = empty
+ | otherwise = ":class: " <> text (unwords classes)
+ return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
blockToRST (CodeBlock (_,classes,kvs) str) = do
opts <- stOptions <$> get
let tabstop = writerTabStop opts
@@ -239,8 +261,7 @@ blockToRST (Table caption _ widths headers rows) = do
middle = hcat $ intersperse sep' blocks
let makeRow = hpipeBlocks . zipWith lblock widthsInChars
let head' = makeRow headers'
- rows' <- mapM (\row -> do cols <- mapM blockListToRST row
- return $ makeRow cols) rows
+ let rows' = map makeRow rawRows
let border ch = char '+' <> char ch <>
(hcat $ intersperse (char ch <> char '+' <> char ch) $
map (\l -> text $ replicate l ch) widthsInChars) <>
@@ -253,7 +274,7 @@ blockToRST (Table caption _ widths headers rows) = do
blockToRST (BulletList items) = do
contents <- mapM bulletListItemToRST items
-- ensure that sublists have preceding blank line
- return $ blankline $$ vcat contents $$ blankline
+ return $ blankline $$ chomp (vcat contents) $$ blankline
blockToRST (OrderedList (start, style', delim) items) = do
let markers = if start == 1 && style' == DefaultStyle && delim == DefaultDelim
then take (length items) $ repeat "#."
@@ -265,11 +286,11 @@ blockToRST (OrderedList (start, style', delim) items) = do
contents <- mapM (\(item, num) -> orderedListItemToRST item num) $
zip markers' items
-- ensure that sublists have preceding blank line
- return $ blankline $$ vcat contents $$ blankline
+ return $ blankline $$ chomp (vcat contents) $$ blankline
blockToRST (DefinitionList items) = do
contents <- mapM definitionListItemToRST items
-- ensure that sublists have preceding blank line
- return $ blankline $$ vcat contents $$ blankline
+ return $ blankline $$ chomp (vcat contents) $$ blankline
-- | Convert bullet list item (list of blocks) to RST.
bulletListItemToRST :: [Block] -> State WriterState Doc
@@ -295,9 +316,19 @@ definitionListItemToRST (label, defs) = do
return $ label' $$ nest tabstop (nestle contents <> cr)
-- | Convert list of Pandoc block elements to RST.
+blockListToRST' :: Bool
+ -> [Block] -- ^ List of block elements
+ -> State WriterState Doc
+blockListToRST' topLevel blocks = do
+ tl <- gets stTopLevel
+ modify (\s->s{stTopLevel=topLevel})
+ res <- vcat `fmap` mapM blockToRST blocks
+ modify (\s->s{stTopLevel=tl})
+ return res
+
blockListToRST :: [Block] -- ^ List of block elements
-> State WriterState Doc
-blockListToRST blocks = mapM blockToRST blocks >>= return . vcat
+blockListToRST = blockListToRST' False
-- | Convert list of Pandoc inline elements to RST.
inlineListToRST :: [Inline] -> State WriterState Doc
@@ -334,12 +365,12 @@ inlineListToRST lst =
okAfterComplex :: Inline -> Bool
okAfterComplex Space = True
okAfterComplex LineBreak = True
- okAfterComplex (Str (c:_)) = isSpace c || c `elem` "-.,:;!?\\/'\")]}>–—"
+ okAfterComplex (Str (c:_)) = isSpace c || c `elem` ("-.,:;!?\\/'\")]}>–—" :: String)
okAfterComplex _ = False
okBeforeComplex :: Inline -> Bool
okBeforeComplex Space = True
okBeforeComplex LineBreak = True
- okBeforeComplex (Str (c:_)) = isSpace c || c `elem` "-:/'\"<([{–—"
+ okBeforeComplex (Str (c:_)) = isSpace c || c `elem` ("-:/'\"<([{–—" :: String)
okBeforeComplex _ = False
isComplex :: Inline -> Bool
isComplex (Emph _) = True
@@ -393,6 +424,9 @@ inlineToRST (Math t str) = do
else blankline $$ (".. math:: " <> text str) $$ blankline
inlineToRST (RawInline f x)
| f == "rst" = return $ text x
+ | f == "latex" || f == "tex" = do
+ modify $ \st -> st{ stHasRawTeX = True }
+ return $ ":raw-latex:`" <> text x <> "`"
| otherwise = return empty
inlineToRST (LineBreak) = return cr -- there's no line break in RST (see Para)
inlineToRST Space = return space
@@ -427,7 +461,7 @@ inlineToRST (Image alternate (source, tit)) = do
return $ "|" <> label <> "|"
inlineToRST (Note contents) = do
-- add to notes in state
- notes <- get >>= return . stNotes
+ notes <- gets stNotes
modify $ \st -> st { stNotes = contents:notes }
let ref = show $ (length notes) + 1
return $ " [" <> text ref <> "]_"
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index 43405ce3c..9eb02ad02 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.RTF
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -56,9 +56,12 @@ rtfEmbedImage opts x@(Image _ (src,_)) = do
"image/jpeg" -> "\\jpegblip"
"image/png" -> "\\pngblip"
_ -> error "Unknown file type"
- let sizeSpec = case imageSize imgdata of
- Nothing -> ""
- Just sz -> "\\picw" ++ show xpx ++
+ sizeSpec <- case imageSize imgdata of
+ Left msg -> do
+ warn $ "Could not determine image size in `" ++
+ src ++ "': " ++ msg
+ return ""
+ Right sz -> return $ "\\picw" ++ show xpx ++
"\\pich" ++ show ypx ++
"\\picwgoal" ++ show (xpt * 20)
++ "\\pichgoal" ++ show (ypt * 20)
@@ -106,7 +109,9 @@ writeRTF options (Pandoc meta@(Meta metamap) blocks) =
$ metadata
in if writerStandalone options
then renderTemplate' (writerTemplate options) context
- else body
+ else case reverse body of
+ ('\n':_) -> body
+ _ -> body ++ "\n"
-- | Construct table of contents from list of header blocks.
tableOfContents :: [Block] -> String
diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs
index 800e741a4..d94dbac46 100644
--- a/src/Text/Pandoc/Writers/Shared.hs
+++ b/src/Text/Pandoc/Writers/Shared.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2013-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Shared
- Copyright : Copyright (C) 2013-2014 John MacFarlane
+ Copyright : Copyright (C) 2013-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index 8ac717bab..2325d1425 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2008-2014 John MacFarlane and Peter Wang
+Copyright (C) 2008-2015 John MacFarlane and Peter Wang
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Texinfo
- Copyright : Copyright (C) 2008-2014 John MacFarlane and Peter Wang
+ Copyright : Copyright (C) 2008-2015 John MacFarlane and Peter Wang
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -120,7 +120,7 @@ inCmd cmd contents = char '@' <> text cmd <> braces contents
-- | Convert Pandoc block element to Texinfo.
blockToTexinfo :: Block -- ^ Block to convert
- -> State WriterState Doc
+ -> State WriterState Doc
blockToTexinfo Null = return empty
@@ -195,9 +195,9 @@ blockToTexinfo HorizontalRule =
-- XXX can't get the equivalent from LaTeX.hs to work
return $ text "@iftex" $$
text "@bigskip@hrule@bigskip" $$
- text "@end iftex" $$
+ text "@end iftex" $$
text "@ifnottex" $$
- text (take 72 $ repeat '-') $$
+ text (take 72 $ repeat '-') $$
text "@end ifnottex"
blockToTexinfo (Header 0 _ lst) = do
@@ -368,7 +368,7 @@ inlineListForNode = return . text . stringToTexinfo .
-- periods, commas, colons, and parentheses are disallowed in node names
disallowedInNode :: Char -> Bool
-disallowedInNode c = c `elem` ".,:()"
+disallowedInNode c = c `elem` (".,:()" :: String)
-- | Convert inline element to Texinfo
inlineToTexinfo :: Inline -- ^ Inline to convert
@@ -421,8 +421,8 @@ inlineToTexinfo (RawInline f str)
return $ text "@tex" $$ text str $$ text "@end tex"
| f == "texinfo" = return $ text str
| otherwise = return empty
-inlineToTexinfo (LineBreak) = return $ text "@*"
-inlineToTexinfo Space = return $ char ' '
+inlineToTexinfo (LineBreak) = return $ text "@*" <> cr
+inlineToTexinfo Space = return space
inlineToTexinfo (Link txt (src@('#':_), _)) = do
contents <- escapeCommas $ inlineListToTexinfo txt
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index 05eb50349..126c1e62e 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Textile
- Copyright : Copyright (C) 2010-2014 John MacFarlane
+ Copyright : Copyright (C) 2010-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -85,6 +85,8 @@ escapeCharForTextile x = case x of
'*' -> "&#42;"
'_' -> "&#95;"
'@' -> "&#64;"
+ '+' -> "&#43;"
+ '-' -> "&#45;"
'|' -> "&#124;"
'\x2014' -> " -- "
'\x2013' -> " - "
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
index 8000368aa..caa13f177 100644
--- a/src/Text/Pandoc/XML.hs
+++ b/src/Text/Pandoc/XML.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.XML
- Copyright : Copyright (C) 2006-2014 John MacFarlane
+ Copyright : Copyright (C) 2006-2015 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/tests/Tests/Old.hs b/tests/Tests/Old.hs
index 8a256b761..047ad0481 100644
--- a/tests/Tests/Old.hs
+++ b/tests/Tests/Old.hs
@@ -18,6 +18,7 @@ import Prelude hiding ( readFile )
import qualified Data.ByteString.Lazy as B
import Text.Pandoc.UTF8 (toStringLazy)
import Text.Printf
+import Text.Pandoc.Error
readFileUTF8 :: FilePath -> IO String
readFileUTF8 f = B.readFile f >>= return . toStringLazy
@@ -130,6 +131,8 @@ tests = [ testGroup "markdown"
"dokuwiki_inline_formatting.native" "dokuwiki_inline_formatting.dokuwiki"
, test "multiblock table" ["-r", "native", "-w", "dokuwiki", "-s"]
"dokuwiki_multiblock_table.native" "dokuwiki_multiblock_table.dokuwiki"
+ , test "external images" ["-r", "native", "-w", "dokuwiki", "-s"]
+ "dokuwiki_external_images.native" "dokuwiki_external_images.dokuwiki"
]
, testGroup "opml"
[ test "basic" ["-r", "native", "-w", "opml", "--columns=78", "-s"]
@@ -153,6 +156,9 @@ tests = [ testGroup "markdown"
, test "formatting" ["-r", "epub", "-w", "native"]
"epub/formatting.epub" "epub/formatting.native"
]
+ , testGroup "twiki"
+ [ test "reader" ["-r", "twiki", "-w", "native", "-s"]
+ "twiki-reader.twiki" "twiki-reader.native" ]
, testGroup "other writers" $ map (\f -> testGroup f $ writerTests f)
[ "opendocument" , "context" , "texinfo", "icml"
, "man" , "plain" , "rtf", "org", "asciidoc"
@@ -177,7 +183,7 @@ lhsReaderTest :: String -> Test
lhsReaderTest format =
testWithNormalize normalizer "lhs" ["-r", format, "-w", "native"]
("lhs-test" <.> format) norm
- where normalizer = writeNative def . normalize . readNative
+ where normalizer = writeNative def . normalize . handleError . readNative
norm = if format == "markdown+lhs"
then "lhs-test-markdown.native"
else "lhs-test.native"
diff --git a/tests/Tests/Readers/Docx.hs b/tests/Tests/Readers/Docx.hs
index 584e7cc94..47292bc99 100644
--- a/tests/Tests/Readers/Docx.hs
+++ b/tests/Tests/Readers/Docx.hs
@@ -13,6 +13,7 @@ import Text.Pandoc.Writers.Native (writeNative)
import qualified Data.Map as M
import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
import Codec.Archive.Zip
+import Text.Pandoc.Error
-- We define a wrapper around pandoc that doesn't normalize in the
-- tests. Since we do our own normalization, we want to make sure
@@ -41,8 +42,8 @@ compareOutput :: ReaderOptions
compareOutput opts docxFile nativeFile = do
df <- B.readFile docxFile
nf <- Prelude.readFile nativeFile
- let (p, _) = readDocx opts df
- return $ (noNorm p, noNorm (readNative nf))
+ let (p, _) = handleError $ readDocx opts df
+ return $ (noNorm p, noNorm (handleError $ readNative nf))
testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO Test
testCompareWithOptsIO opts name docxFile nativeFile = do
@@ -79,7 +80,7 @@ compareMediaPathIO mediaPath mediaBag docxPath = do
compareMediaBagIO :: FilePath -> IO Bool
compareMediaBagIO docxFile = do
df <- B.readFile docxFile
- let (_, mb) = readDocx def df
+ let (_, mb) = handleError $ readDocx def df
bools <- mapM
(\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
(mediaDirectory mb)
@@ -114,6 +115,10 @@ tests = [ testGroup "inlines"
"docx/image.docx"
"docx/image_no_embed.native"
, testCompare
+ "VML image"
+ "docx/image_vml.docx"
+ "docx/image_vml.native"
+ , testCompare
"inline image in links"
"docx/inline_images.docx"
"docx/inline_images.native"
@@ -141,6 +146,10 @@ tests = [ testGroup "inlines"
"inline code (with VerbatimChar style)"
"docx/inline_code.docx"
"docx/inline_code.native"
+ , testCompare
+ "inline code in subscript and superscript"
+ "docx/verbatim_subsuper.docx"
+ "docx/verbatim_subsuper.native"
]
, testGroup "blocks"
[ testCompare
@@ -156,9 +165,9 @@ tests = [ testGroup "inlines"
"docx/numbered_header.docx"
"docx/numbered_header.native"
, testCompare
- "headers in other languages"
- "docx/danish_headers.docx"
- "docx/danish_headers.native"
+ "i18n blocks (headers and blockquotes)"
+ "docx/i18n_blocks.docx"
+ "docx/i18n_blocks.native"
, testCompare
"lists"
"docx/lists.docx"
@@ -168,6 +177,10 @@ tests = [ testGroup "inlines"
"docx/definition_list.docx"
"docx/definition_list.native"
, testCompare
+ "custom defined lists in styles"
+ "docx/german_styled_lists.docx"
+ "docx/german_styled_lists.native"
+ , testCompare
"footnotes and endnotes"
"docx/notes.docx"
"docx/notes.native"
@@ -184,6 +197,10 @@ tests = [ testGroup "inlines"
"docx/tables.docx"
"docx/tables.native"
, testCompare
+ "tables with lists in cells"
+ "docx/table_with_list_cell.docx"
+ "docx/table_with_list_cell.native"
+ , testCompare
"code block"
"docx/codeblock.docx"
"docx/codeblock.native"
diff --git a/tests/Tests/Readers/EPUB.hs b/tests/Tests/Readers/EPUB.hs
index 0d19a8400..033352d51 100644
--- a/tests/Tests/Readers/EPUB.hs
+++ b/tests/Tests/Readers/EPUB.hs
@@ -8,10 +8,10 @@ import qualified Data.ByteString.Lazy as BL
import Text.Pandoc.Readers.EPUB
import Text.Pandoc.MediaBag (MediaBag, mediaDirectory)
import Control.Applicative
-import System.FilePath (joinPath)
+import Text.Pandoc.Error
getMediaBag :: FilePath -> IO MediaBag
-getMediaBag fp = snd . readEPUB def <$> BL.readFile fp
+getMediaBag fp = snd . handleError . readEPUB def <$> BL.readFile fp
testMediaBag :: FilePath -> [(String, String, Int)] -> IO ()
testMediaBag fp bag = do
@@ -23,7 +23,11 @@ testMediaBag fp bag = do
(actBag == bag)
featuresBag :: [(String, String, Int)]
-featuresBag = [(joinPath ["img","check.gif"],"image/gif",1340),(joinPath ["img","check.jpg"],"image/jpeg",2661),(joinPath ["img","check.png"],"image/png",2815),(joinPath ["img","multiscripts_and_greek_alphabet.png"],"image/png",10060)]
+featuresBag = [("img/check.gif","image/gif",1340)
+ ,("img/check.jpg","image/jpeg",2661)
+ ,("img/check.png","image/png",2815)
+ ,("img/multiscripts_and_greek_alphabet.png","image/png",10060)
+ ]
tests :: [Test]
tests =
diff --git a/tests/Tests/Readers/HTML.hs b/tests/Tests/Readers/HTML.hs
new file mode 100644
index 000000000..2eb87a2f3
--- /dev/null
+++ b/tests/Tests/Readers/HTML.hs
@@ -0,0 +1,27 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Readers.HTML (tests) where
+
+import Text.Pandoc.Definition
+import Test.Framework
+import Tests.Helpers
+import Tests.Arbitrary()
+import Text.Pandoc.Builder
+import Text.Pandoc
+import Text.Pandoc.Error
+
+html :: String -> Pandoc
+html = handleError . readHtml def
+
+tests :: [Test]
+tests = [ testGroup "base tag"
+ [ test html "simple" $
+ "<head><base href=\"http://www.w3schools.com/images\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
+ , test html "slash at end of base" $
+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
+ , test html "absolute URL" $
+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?>
+ plain (image "http://example.com/stickman.gif" "" (text "Stickman"))
+ ]
+ ]
diff --git a/tests/Tests/Readers/LaTeX.hs b/tests/Tests/Readers/LaTeX.hs
index 8ff23ebc1..b72d707e7 100644
--- a/tests/Tests/Readers/LaTeX.hs
+++ b/tests/Tests/Readers/LaTeX.hs
@@ -7,15 +7,21 @@ import Tests.Helpers
import Tests.Arbitrary()
import Text.Pandoc.Builder
import Text.Pandoc
+import Data.Monoid (mempty)
+import Text.Pandoc.Error
latex :: String -> Pandoc
-latex = readLaTeX def
+latex = handleError . readLaTeX def
infix 4 =:
(=:) :: ToString c
=> String -> (String, c) -> Test
(=:) = test latex
+simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
+simpleTable' aligns = table "" (zip aligns (repeat 0.0))
+ (map (const mempty) aligns)
+
tests :: [Test]
tests = [ testGroup "basic"
[ "simple" =:
@@ -62,10 +68,54 @@ tests = [ testGroup "basic"
"\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock ""
]
+ , testGroup "tables"
+ [ "Single cell table" =:
+ "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?>
+ simpleTable' [AlignLeft] [[plain "Test"]]
+ , "Multi cell table" =:
+ "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Multi line table" =:
+ unlines [ "\\begin{tabular}{|c|}"
+ , "One\\\\"
+ , "Two\\\\"
+ , "Three\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignCenter]
+ [[plain "One"], [plain "Two"], [plain "Three"]]
+ , "Empty table" =:
+ "\\begin{tabular}{}\\end{tabular}" =?>
+ simpleTable' [] []
+ , "Table with fixed column width" =:
+ "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]]
+ , "Table with empty column separators" =:
+ "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with custom column separators" =:
+ unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
+ , "One&Two\\\\"
+ , "\\end{tabular}" ] =?>
+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
+ , "Table with vertical alignment argument" =:
+ "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
+ simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
+ ]
+
, testGroup "citations"
[ natbibCitations
, biblatexCitations
]
+
+ , let hex = ['0'..'9']++['a'..'f'] in
+ testGroup "Character Escapes"
+ [ "Two-character escapes" =:
+ concat ["^^"++[i,j] | i <- hex, j <- hex] =?>
+ para (str ['\0'..'\255'])
+ , "One-character escapes" =:
+ concat ["^^"++[i] | i <- hex] =?>
+ para (str $ ['p'..'y']++['!'..'&'])
+ ]
]
baseCitation :: Citation
diff --git a/tests/Tests/Readers/Markdown.hs b/tests/Tests/Readers/Markdown.hs
index b45d94032..5b39ae7e2 100644
--- a/tests/Tests/Readers/Markdown.hs
+++ b/tests/Tests/Readers/Markdown.hs
@@ -9,17 +9,21 @@ import Text.Pandoc.Builder
import qualified Data.Set as Set
-- import Text.Pandoc.Shared ( normalize )
import Text.Pandoc
+import Text.Pandoc.Error
markdown :: String -> Pandoc
-markdown = readMarkdown def
+markdown = handleError . readMarkdown def
markdownSmart :: String -> Pandoc
-markdownSmart = readMarkdown def { readerSmart = True }
+markdownSmart = handleError . readMarkdown def { readerSmart = True }
markdownCDL :: String -> Pandoc
-markdownCDL = readMarkdown def { readerExtensions = Set.insert
+markdownCDL = handleError . readMarkdown def { readerExtensions = Set.insert
Ext_compact_definition_lists $ readerExtensions def }
+markdownGH :: String -> Pandoc
+markdownGH = handleError . readMarkdown def { readerExtensions = githubMarkdownExtensions }
+
infix 4 =:
(=:) :: ToString c
=> String -> (String, c) -> Test
@@ -27,7 +31,7 @@ infix 4 =:
testBareLink :: (String, Inlines) -> Test
testBareLink (inp, ils) =
- test (readMarkdown def{ readerExtensions =
+ test (handleError . readMarkdown def{ readerExtensions =
Set.fromList [Ext_autolink_bare_uris, Ext_raw_html] })
inp (inp, doc $ para ils)
@@ -115,6 +119,10 @@ bareLinkTests =
autolink "http://business.timesonline.co.uk/article/0,,9065-2473189,00.html")
, ("http://www.mail-archive.com/ruby-talk@ruby-lang.org/",
autolink "http://www.mail-archive.com/ruby-talk@ruby-lang.org/")
+ , ("https://example.org/?anchor=lala-",
+ autolink "https://example.org/?anchor=lala-")
+ , ("https://example.org/?anchor=-lala",
+ autolink "https://example.org/?anchor=-lala")
]
{-
@@ -165,6 +173,12 @@ tests = [ testGroup "inline code"
"<del>test</del>" =?>
rawBlock "html" "<del>" <> plain (str "test") <>
rawBlock "html" "</del>"
+ , "invalid tag (issue #1820" =:
+ "</ div></.div>" =?>
+ para (text "</ div></.div>")
+ , "technically invalid comment" =:
+ "<!-- pandoc --help -->" =?>
+ rawBlock "html" "<!-- pandoc --help -->"
]
, "unbalanced brackets" =:
"[[[[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[[[[hi")
@@ -183,11 +197,63 @@ tests = [ testGroup "inline code"
=?> para (link "/there.0" "" "hi")
]
, testGroup "bare URIs"
- (map testBareLink bareLinkTests)
+ (map testBareLink bareLinkTests)
+ , testGroup "autolinks"
+ [ "with unicode dash following" =:
+ "<http://foo.bar>\8212" =?> para (autolink "http://foo.bar" <>
+ str "\8212")
+ , "a partial URL (#2277)" =:
+ "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>" =?>
+ para (text "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>")
+ ]
+ , testGroup "links"
+ [ "no autolink inside link" =:
+ "[<https://example.org>](url)" =?>
+ para (link "url" "" (text "<https://example.org>"))
+ , "no inline link inside link" =:
+ "[[a](url2)](url)" =?>
+ para (link "url" "" (text "[a](url2)"))
+ , "no bare URI inside link" =:
+ "[https://example.org(](url)" =?>
+ para (link "url" "" (text "https://example.org("))
+ ]
, testGroup "Headers"
[ "blank line before header" =:
"\n# Header\n"
=?> headerWith ("header",[],[]) 1 "Header"
+ , "bracketed text (#2062)" =:
+ "# [hi]\n"
+ =?> headerWith ("hi",[],[]) 1 "[hi]"
+ , "ATX header without trailing #s" =:
+ "# Foo bar\n\n" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ , "ATX header without trailing #s" =:
+ "# Foo bar with # #" =?>
+ headerWith ("foo-bar-with",[],[]) 1 "Foo bar with #"
+ , "setext header" =:
+ "Foo bar\n=\n\n Foo bar 2 \n=" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ <> headerWith ("foo-bar-2",[],[]) 1 "Foo bar 2"
+ ]
+ , testGroup "Implicit header references"
+ [ "ATX header without trailing #s" =:
+ "# Header\n[header]\n\n[header ]\n\n[ header]" =?>
+ headerWith ("header",[],[]) 1 "Header"
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ , "ATX header with trailing #s" =:
+ "# Foo bar #\n[foo bar]\n\n[foo bar ]\n\n[ foo bar]" =?>
+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ <> para (link "#foo-bar" "" (text "foo bar"))
+ , "setext header" =:
+ " Header \n=\n\n[header]\n\n[header ]\n\n[ header]" =?>
+ headerWith ("header",[],[]) 1 "Header"
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
+ <> para (link "#header" "" (text "header"))
]
, testGroup "smart punctuation"
[ test markdownSmart "quote before ellipses"
@@ -199,6 +265,9 @@ tests = [ testGroup "inline code"
, test markdownSmart "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 markdownSmart "apostrophe after math" $ -- issue #1909
+ "The value of the $x$'s and the systems' condition." =?>
+ para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
]
, testGroup "footnotes"
[ "indent followed by newline and flush-left text" =:
@@ -212,7 +281,7 @@ tests = [ testGroup "inline code"
=?> para (note (para "See [^1]"))
]
, testGroup "lhs"
- [ test (readMarkdown def{ readerExtensions = Set.insert
+ [ test (handleError . readMarkdown def{ readerExtensions = Set.insert
Ext_literate_haskell $ readerExtensions def })
"inverse bird tracks and html" $
"> a\n\n< b\n\n<div>\n"
@@ -255,6 +324,16 @@ tests = [ testGroup "inline code"
definitionList [ (text "foo1", [para (text "bar") <>
para (text "baz")])
]
+ , "first line not indented" =:
+ "foo\n: bar\n" =?>
+ definitionList [ (text "foo", [plain (text "bar")]) ]
+ , "list in definition" =:
+ "foo\n: - bar\n" =?>
+ definitionList [ (text "foo", [bulletList [plain (text "bar")]]) ]
+ , "in div" =:
+ "<div>foo\n: - bar\n</div>" =?>
+ divWith nullAttr (definitionList
+ [ (text "foo", [bulletList [plain (text "bar")]]) ])
]
, testGroup "+compact_definition_lists"
[ test markdownCDL "basic compact list" $
@@ -271,5 +350,77 @@ tests = [ testGroup "inline code"
plain (text "if this button exists") <>
rawBlock "html" "</button>" <>
divWith nullAttr (para $ text "with this div too.")]
+ , test markdownGH "issue #1636" $
+ unlines [ "* a"
+ , "* b"
+ , "* c"
+ , " * d" ]
+ =?>
+ bulletList [ plain "a"
+ , plain "b"
+ , plain "c" <> bulletList [plain "d"] ]
+ ]
+ , testGroup "citations"
+ [ "simple" =:
+ "@item1" =?> para (cite [
+ Citation{ citationId = "item1"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ ] "@item1")
+ , "key starts with digit" =:
+ "@1657:huyghens" =?> para (cite [
+ Citation{ citationId = "1657:huyghens"
+ , citationPrefix = []
+ , citationSuffix = []
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ ] "@1657:huyghens")
+ ]
+ , let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita")
+ in testGroup "footnote/link following citation" -- issue #2083
+ [ "footnote" =:
+ unlines [ "@cita[^note]"
+ , ""
+ , "[^note]: note" ] =?>
+ para (
+ citation <> note (para $ str "note")
+ )
+ , "normal link" =:
+ "@cita [link](http://www.com)" =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "reference link" =:
+ unlines [ "@cita [link][link]"
+ , ""
+ , "[link]: http://www.com" ] =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "short reference link" =:
+ unlines [ "@cita [link]"
+ , ""
+ , "[link]: http://www.com" ] =?>
+ para (
+ citation <> space <> link "http://www.com" "" (str "link")
+ )
+ , "implicit header link" =:
+ unlines [ "# Header"
+ , "@cita [Header]" ] =?>
+ headerWith ("header",[],[]) 1 (str "Header") <> para (
+ citation <> space <> link "#header" "" (str "Header")
+ )
+ , "regular citation" =:
+ "@cita [foo]" =?>
+ para (
+ cite [Citation "cita" [] [Str "foo"] AuthorInText 0 0]
+ (str "@cita" <> space <> str "[foo]")
+ )
]
]
diff --git a/tests/Tests/Readers/Odt.hs b/tests/Tests/Readers/Odt.hs
new file mode 100644
index 000000000..cf30b8398
--- /dev/null
+++ b/tests/Tests/Readers/Odt.hs
@@ -0,0 +1,165 @@
+module Tests.Readers.Odt (tests) where
+
+import Control.Monad ( liftM )
+import Text.Pandoc.Options
+import Text.Pandoc.Readers.Native
+import Text.Pandoc.Readers.Markdown
+import Text.Pandoc.Definition
+import Text.Pandoc.Error
+import Tests.Helpers
+import Test.Framework
+--import Test.HUnit (assertBool)
+--import Test.Framework.Providers.HUnit
+import qualified Data.ByteString.Lazy as B
+import Text.Pandoc.Readers.Odt
+import Text.Pandoc.Writers.Native (writeNative)
+import qualified Data.Map as M
+--import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
+--import Codec.Archive.Zip
+
+
+tests :: [Test]
+tests = testsComparingToMarkdown ++ testsComparingToNative
+
+testsComparingToMarkdown :: [Test]
+testsComparingToMarkdown = map nameToTest namesOfTestsComparingToMarkdown
+ where nameToTest name = createTest
+ compareOdtToMarkdown
+ name
+ (toOdtPath name)
+ (toMarkdownPath name)
+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
+ toMarkdownPath name = "odt/markdown/" ++ name ++ ".md"
+
+testsComparingToNative :: [Test]
+testsComparingToNative = map nameToTest namesOfTestsComparingToNative
+ where nameToTest name = createTest
+ compareOdtToNative
+ name
+ (toOdtPath name)
+ (toNativePath name)
+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
+ toNativePath name = "odt/native/" ++ name ++ ".native"
+
+
+newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
+ deriving ( Show )
+
+instance ToString NoNormPandoc where
+ toString d = writeNative def{ writerStandalone = s } $ toPandoc d
+ where s = case d of
+ NoNormPandoc (Pandoc (Meta m) _)
+ | M.null m -> False
+ | otherwise -> True
+
+instance ToPandoc NoNormPandoc where
+ toPandoc = unNoNorm
+
+getNoNormVia :: (a -> Pandoc) -> String -> Either PandocError a -> NoNormPandoc
+getNoNormVia _ readerName (Left _) = error (readerName ++ " reader failed")
+getNoNormVia f _ (Right a) = NoNormPandoc (f a)
+
+type TestCreator = ReaderOptions
+ -> FilePath -> FilePath
+ -> IO (NoNormPandoc, NoNormPandoc)
+
+compareOdtToNative :: TestCreator
+compareOdtToNative opts odtPath nativePath = do
+ nativeFile <- Prelude.readFile nativePath
+ odtFile <- B.readFile odtPath
+ let native = getNoNormVia id "native" $ readNative nativeFile
+ let odt = getNoNormVia fst "odt" $ readOdt opts odtFile
+ return (odt,native)
+
+compareOdtToMarkdown :: TestCreator
+compareOdtToMarkdown opts odtPath markdownPath = do
+ markdownFile <- Prelude.readFile markdownPath
+ odtFile <- B.readFile odtPath
+ let markdown = getNoNormVia id "markdown" $ readMarkdown opts markdownFile
+ let odt = getNoNormVia fst "odt" $ readOdt opts odtFile
+ return (odt,markdown)
+
+
+createTest :: TestCreator
+ -> TestName
+ -> FilePath -> FilePath
+ -> Test
+createTest creator name path1 path2 =
+ buildTest $ liftM (test id name) (creator def path1 path2)
+
+{-
+--
+
+getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
+getMedia archivePath mediaPath = do
+ zf <- B.readFile archivePath >>= return . toArchive
+ return $ findEntryByPath ("Pictures/" ++ mediaPath) zf >>= (Just . fromEntry)
+
+compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
+compareMediaPathIO mediaPath mediaBag odtPath = do
+ odtMedia <- getMedia odtPath mediaPath
+ let mbBS = case lookupMedia mediaPath mediaBag of
+ Just (_, bs) -> bs
+ Nothing -> error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")
+ odtBS = case odtMedia of
+ Just bs -> bs
+ Nothing -> error ("couldn't find " ++
+ mediaPath ++
+ " in media bag")
+ return $ mbBS == odtBS
+
+compareMediaBagIO :: FilePath -> IO Bool
+compareMediaBagIO odtFile = do
+ df <- B.readFile odtFile
+ let (_, mb) = readOdt def df
+ bools <- mapM
+ (\(fp, _, _) -> compareMediaPathIO fp mb odtFile)
+ (mediaDirectory mb)
+ return $ and bools
+
+testMediaBagIO :: String -> FilePath -> IO Test
+testMediaBagIO name odtFile = do
+ outcome <- compareMediaBagIO odtFile
+ return $ testCase name (assertBool
+ ("Media didn't match media bag in file " ++ odtFile)
+ outcome)
+
+testMediaBag :: String -> FilePath -> Test
+testMediaBag name odtFile = buildTest $ testMediaBagIO name odtFile
+-}
+--
+
+
+
+namesOfTestsComparingToMarkdown :: [ String ]
+namesOfTestsComparingToMarkdown = [ "bold"
+-- , "citation"
+ , "endnote"
+ , "externalLink"
+ , "footnote"
+ , "headers"
+-- , "horizontalRule"
+-- , "image"
+ , "italic"
+-- , "listBlocks"
+ , "paragraph"
+ , "strikeout"
+-- , "trackedChanges"
+ , "underlined"
+ ]
+
+namesOfTestsComparingToNative :: [ String ]
+namesOfTestsComparingToNative = [ "blockquote"
+ , "orderedListMixed"
+ , "orderedListRoman"
+ , "orderedListSimple"
+ , "referenceToChapter"
+ , "referenceToListItem"
+ , "referenceToText"
+ , "simpleTable"
+-- , "table"
+ , "unicode"
+ , "unorderedList"
+ ] \ No newline at end of file
diff --git a/tests/Tests/Readers/Org.hs b/tests/Tests/Readers/Org.hs
index 92ec8155b..92e6993df 100644
--- a/tests/Tests/Readers/Org.hs
+++ b/tests/Tests/Readers/Org.hs
@@ -4,14 +4,17 @@ module Tests.Readers.Org (tests) where
import Text.Pandoc.Definition
import Test.Framework
import Tests.Helpers
-import Tests.Arbitrary()
import Text.Pandoc.Builder
import Text.Pandoc
import Data.List (intersperse)
import Data.Monoid (mempty, mappend, mconcat)
+import Text.Pandoc.Error
org :: String -> Pandoc
-org = readOrg def
+org = handleError . readOrg def
+
+orgSmart :: String -> Pandoc
+orgSmart = handleError . readOrg def { readerSmart = True }
infix 4 =:
(=:) :: ToString c
@@ -126,6 +129,14 @@ tests =
, (emph "b") <> "."
])
+ , "Quotes are forbidden border chars" =:
+ "/'nope/ *nope\"*" =?>
+ para ("/'nope/" <> space <> "*nope\"*")
+
+ , "Commata are forbidden border chars" =:
+ "/nada,/" =?>
+ para "/nada,/"
+
, "Markup should work properly after a blank line" =:
unlines ["foo", "", "/bar/"] =?>
(para $ text "foo") <> (para $ emph $ text "bar")
@@ -189,10 +200,26 @@ tests =
"[[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][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"
@@ -207,6 +234,14 @@ tests =
, "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 <>
@@ -268,6 +303,18 @@ tests =
"\\notacommand{foo}" =?>
para (rawInline "latex" "\\notacommand{foo}")
+ , "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 "©"
+
, "LaTeX citation" =:
"\\cite{Coffee}" =?>
let citation = Citation
@@ -450,6 +497,40 @@ tests =
, header 2 ("walk" <> space <> "dog")
]
+ , "Tagged headers" =:
+ unlines [ "* Personal :PERSONAL:"
+ , "** Call Mom :@PHONE:"
+ , "** Call John :@PHONE:JOHN: "
+ ] =?>
+ let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
+ in mconcat [ header 1 ("Personal" <> tagSpan "PERSONAL")
+ , header 2 ("Call Mom" <> tagSpan "@PHONE")
+ , header 2 ("Call John" <> tagSpan "@PHONE" <> tagSpan "JOHN")
+ ]
+
+ , "Untagged header containing colons" =:
+ "* This: is not: tagged" =?>
+ header 1 "This: is not: tagged"
+
+ , "Comment Trees" =:
+ unlines [ "* COMMENT A comment tree"
+ , " Not much going on here"
+ , "** This will be dropped"
+ , "* Comment tree above"
+ ] =?>
+ header 1 "Comment tree above"
+
+ , "Nothing but a COMMENT header" =:
+ "* COMMENT Test" =?>
+ (mempty::Blocks)
+
+ , "Tree with :noexport:" =:
+ unlines [ "* Should be ignored :archive:noexport:old:"
+ , "** Old stuff"
+ , " This is not going to be exported"
+ ] =?>
+ (mempty::Blocks)
+
, "Paragraph starting with an asterisk" =:
"*five" =?>
para "*five"
@@ -578,6 +659,13 @@ tests =
, plain "Item2"
]
+ , "Unindented *" =:
+ ("- Item1\n" ++
+ "* Item2\n") =?>
+ bulletList [ plain "Item1"
+ ] <>
+ header 1 "Item2"
+
, "Multi-line Bullet Lists" =:
("- *Fat\n" ++
" Tony*\n" ++
@@ -622,6 +710,33 @@ tests =
]
]
+ , "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")
+ ]
+ , header 1 "Homework"
+ ]
+
+ , "Bullet List Unindented with trailing Header" =:
+ ("- Discovery\n\
+ \- Homework\n\
+ \* NotValidListItem") =?>
+ mconcat [ bulletList [ plain "Discovery"
+ , plain "Homework"
+ ]
+ , header 1 "NotValidListItem"
+ ]
+
, "Simple Ordered List" =:
("1. Item1\n" ++
"2. Item2\n") =?>
@@ -717,6 +832,16 @@ tests =
, ("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"])
+ ]
+ , header 1 "header"
+ ]
+
, "Loose bullet list" =:
unlines [ "- apple"
, ""
@@ -1057,4 +1182,25 @@ tests =
]
in codeBlockWith ( "", classes, 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—"))
+ ]
]
diff --git a/tests/Tests/Readers/RST.hs b/tests/Tests/Readers/RST.hs
index a80dc32b7..48abc16f8 100644
--- a/tests/Tests/Readers/RST.hs
+++ b/tests/Tests/Readers/RST.hs
@@ -7,10 +7,11 @@ import Tests.Helpers
import Tests.Arbitrary()
import Text.Pandoc.Builder
import Text.Pandoc
+import Text.Pandoc.Error
import Data.Monoid (mempty)
rst :: String -> Pandoc
-rst = readRST def{ readerStandalone = True }
+rst = handleError . readRST def{ readerStandalone = True }
infix 4 =:
(=:) :: ToString c
@@ -21,7 +22,8 @@ tests :: [Test]
tests = [ "line block with blank line" =:
"| a\n|\n| b" =?> para (str "a") <>
para (str "\160b")
- , "field list" =: unlines
+ , testGroup "field list"
+ [ "general" =: unlines
[ "para"
, ""
, ":Hostname: media08"
@@ -35,17 +37,17 @@ tests = [ "line block with blank line" =:
, ":Parameter i: integer"
, ":Final: item"
, " on two lines" ]
- =?> ( doc
- $ para "para" <>
- definitionList [ (str "Hostname", [para "media08"])
- , (str "IP address", [para "10.0.0.19"])
- , (str "Size", [para "3ru"])
- , (str "Version", [para "1"])
- , (str "Indentation", [para "Since the field marker may be quite long, the second and subsequent lines of the field body do not have to line up with the first line, but they must be indented relative to the field name marker, and they must line up with each other."])
- , (str "Parameter i", [para "integer"])
- , (str "Final", [para "item on two lines"])
- ])
- , "initial field list" =: unlines
+ =?> ( doc
+ $ para "para" <>
+ definitionList [ (str "Hostname", [para "media08"])
+ , (text "IP address", [para "10.0.0.19"])
+ , (str "Size", [para "3ru"])
+ , (str "Version", [para "1"])
+ , (str "Indentation", [para "Since the field marker may be quite long, the second and subsequent lines of the field body do not have to line up with the first line, but they must be indented relative to the field name marker, and they must line up with each other."])
+ , (text "Parameter i", [para "integer"])
+ , (str "Final", [para "item on two lines"])
+ ])
+ , "metadata" =: unlines
[ "====="
, "Title"
, "====="
@@ -55,10 +57,31 @@ tests = [ "line block with blank line" =:
, ""
, ":Version: 1"
]
- =?> ( setMeta "version" (para "1")
- $ setMeta "title" ("Title" :: Inlines)
- $ setMeta "subtitle" ("Subtitle" :: Inlines)
- $ doc mempty )
+ =?> ( setMeta "version" (para "1")
+ $ setMeta "title" ("Title" :: Inlines)
+ $ setMeta "subtitle" ("Subtitle" :: Inlines)
+ $ doc mempty )
+ , "with inline markup" =: unlines
+ [ ":*Date*: today"
+ , ""
+ , ".."
+ , ""
+ , ":*one*: emphasis"
+ , ":two_: reference"
+ , ":`three`_: another one"
+ , ":``four``: literal"
+ , ""
+ , ".. _two: http://example.com"
+ , ".. _three: http://example.org"
+ ]
+ =?> ( setMeta "date" (str "today")
+ $ doc
+ $ definitionList [ (emph "one", [para "emphasis"])
+ , (link "http://example.com" "" "two", [para "reference"])
+ , (link "http://example.org" "" "three", [para "another one"])
+ , (code "four", [para "literal"])
+ ])
+ ]
, "URLs with following punctuation" =:
("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" ++
"http://foo.bar/baz_(bam) (http://foo.bar)") =?>
@@ -67,5 +90,49 @@ tests = [ "line block with blank line" =:
link "http://foo.bar.baz" "" "http://foo.bar.baz" <> ". " <>
link "http://foo.bar/baz_(bam)" "" "http://foo.bar/baz_(bam)"
<> " (" <> link "http://foo.bar" "" "http://foo.bar" <> ")")
+ , "Reference names with special characters" =:
+ ("A-1-B_2_C:3:D+4+E.5.F_\n\n" ++
+ ".. _A-1-B_2_C:3:D+4+E.5.F: https://example.com\n") =?>
+ para (link "https://example.com" "" "A-1-B_2_C:3:D+4+E.5.F")
+ , testGroup "literal / line / code blocks"
+ [ "indented literal block" =: unlines
+ [ "::"
+ , ""
+ , " block quotes"
+ , ""
+ , " can go on for many lines"
+ , "but must stop here"]
+ =?> (doc $
+ codeBlock "block quotes\n\ncan go on for many lines" <>
+ para "but must stop here")
+ , "line block with 3 lines" =: "| a\n| b\n| c"
+ =?> para ("a" <> linebreak <> "b" <> linebreak <> "c")
+ , "quoted literal block using >" =: "::\n\n> quoted\n> block\n\nOrdinary paragraph"
+ =?> codeBlock "> quoted\n> block" <> para "Ordinary paragraph"
+ , "quoted literal block using | (not a line block)" =: "::\n\n| quoted\n| block\n\nOrdinary paragraph"
+ =?> codeBlock "| quoted\n| block" <> para "Ordinary paragraph"
+ , "class directive with single paragraph" =: ".. class:: special\n\nThis is a \"special\" paragraph."
+ =?> divWith ("", ["special"], []) (para "This is a \"special\" paragraph.")
+ , "class directive with two paragraphs" =: ".. class:: exceptional remarkable\n\n First paragraph.\n\n Second paragraph."
+ =?> divWith ("", ["exceptional", "remarkable"], []) (para "First paragraph." <> para "Second paragraph.")
+ , "class directive around literal block" =: ".. class:: classy\n\n::\n\n a\n b"
+ =?> divWith ("", ["classy"], []) (codeBlock "a\nb")]
+ , testGroup "interpreted text roles"
+ [ "literal role prefix" =: ":literal:`a`" =?> para (code "a")
+ , "literal role postfix" =: "`a`:literal:" =?> para (code "a")
+ , "literal text" =: "``text``" =?> para (code "text")
+ , "code role" =: ":code:`a`" =?> para (codeWith ("", ["sourceCode"], []) "a")
+ , "inherited code role" =: ".. role:: codeLike(code)\n\n:codeLike:`a`"
+ =?> para (codeWith ("", ["codeLike", "sourceCode"], []) "a")
+ , "custom code role with language field"
+ =: ".. role:: lhs(code)\n :language: haskell\n\n:lhs:`a`"
+ =?> para (codeWith ("", ["lhs", "haskell","sourceCode"], []) "a")
+ , "custom role with unspecified parent role"
+ =: ".. role:: classy\n\n:classy:`text`"
+ =?> para (spanWith ("", ["classy"], []) "text")
+ , "role with recursive inheritance"
+ =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`"
+ =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text")
+ , "unknown role" =: ":unknown:`text`" =?> para (str "text")
+ ]
]
-
diff --git a/tests/Tests/Readers/Txt2Tags.hs b/tests/Tests/Readers/Txt2Tags.hs
index fd7c767e0..938a2b455 100644
--- a/tests/Tests/Readers/Txt2Tags.hs
+++ b/tests/Tests/Readers/Txt2Tags.hs
@@ -7,12 +7,13 @@ import Tests.Helpers
import Tests.Arbitrary()
import Text.Pandoc.Builder
import Text.Pandoc
+import Text.Pandoc.Error
import Data.List (intersperse)
import Data.Monoid (mempty, mconcat)
import Text.Pandoc.Readers.Txt2Tags
t2t :: String -> Pandoc
-t2t s = readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def s
+t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def
infix 4 =:
(=:) :: ToString c
diff --git a/tests/Tests/Writers/Docx.hs b/tests/Tests/Writers/Docx.hs
new file mode 100644
index 000000000..068c5a935
--- /dev/null
+++ b/tests/Tests/Writers/Docx.hs
@@ -0,0 +1,129 @@
+module Tests.Writers.Docx (tests) where
+
+import Text.Pandoc.Options
+import Text.Pandoc.Readers.Native
+import Text.Pandoc.Definition
+import Tests.Helpers
+import Test.Framework
+import Text.Pandoc.Readers.Docx
+import Text.Pandoc.Writers.Docx
+import Text.Pandoc.Error
+
+type Options = (WriterOptions, ReaderOptions)
+
+compareOutput :: Options
+ -> FilePath
+ -> IO (Pandoc, Pandoc)
+compareOutput opts nativeFile = do
+ nf <- Prelude.readFile nativeFile
+ df <- writeDocx (fst opts) (handleError $ readNative nf)
+ let (p, _) = handleError $ readDocx (snd opts) df
+ return (p, handleError $ readNative nf)
+
+testCompareWithOptsIO :: Options -> String -> FilePath -> IO Test
+testCompareWithOptsIO opts name nativeFile = do
+ (dp, np) <- compareOutput opts nativeFile
+ return $ test id name (dp, np)
+
+testCompareWithOpts :: Options -> String -> FilePath -> Test
+testCompareWithOpts opts name nativeFile =
+ buildTest $ testCompareWithOptsIO opts name nativeFile
+
+testCompare :: String -> FilePath -> Test
+testCompare = testCompareWithOpts def
+
+tests :: [Test]
+tests = [ testGroup "inlines"
+ [ testCompare
+ "font formatting"
+ "docx/inline_formatting_writer.native"
+ , testCompare
+ "font formatting with character styles"
+ "docx/char_styles.native"
+ , testCompare
+ "hyperlinks"
+ "docx/links_writer.native"
+ , testCompare
+ "inline image"
+ "docx/image_no_embed_writer.native"
+ , testCompare
+ "inline image in links"
+ "docx/inline_images_writer.native"
+ , testCompare
+ "handling unicode input"
+ "docx/unicode.native"
+ , testCompare
+ "literal tabs"
+ "docx/tabs.native"
+ , testCompare
+ "normalizing inlines"
+ "docx/normalize.native"
+ , testCompare
+ "normalizing inlines deep inside blocks"
+ "docx/deep_normalize.native"
+ , testCompare
+ "move trailing spaces outside of formatting"
+ "docx/trailing_spaces_in_formatting.native"
+ , testCompare
+ "inline code (with VerbatimChar style)"
+ "docx/inline_code.native"
+ , testCompare
+ "inline code in subscript and superscript"
+ "docx/verbatim_subsuper.native"
+ ]
+ , testGroup "blocks"
+ [ testCompare
+ "headers"
+ "docx/headers.native"
+ , testCompare
+ "headers already having auto identifiers"
+ "docx/already_auto_ident.native"
+ , testCompare
+ "numbered headers automatically made into list"
+ "docx/numbered_header.native"
+ , testCompare
+ "i18n blocks (headers and blockquotes)"
+ "docx/i18n_blocks.native"
+ -- Continuation does not survive round-trip
+ , testCompare
+ "lists"
+ "docx/lists_writer.native"
+ , testCompare
+ "definition lists"
+ "docx/definition_list.native"
+ , testCompare
+ "custom defined lists in styles"
+ "docx/german_styled_lists.native"
+ , testCompare
+ "footnotes and endnotes"
+ "docx/notes.native"
+ , testCompare
+ "blockquotes (parsing indent as blockquote)"
+ "docx/block_quotes_parse_indent.native"
+ , testCompare
+ "hanging indents"
+ "docx/hanging_indent.native"
+ -- tables headers do not survive round-trip, should look into that
+ , testCompare
+ "tables"
+ "docx/tables.native"
+ , testCompare
+ "tables with lists in cells"
+ "docx/table_with_list_cell.native"
+ , testCompare
+ "code block"
+ "docx/codeblock.native"
+ , testCompare
+ "dropcap paragraphs"
+ "docx/drop_cap.native"
+ ]
+ , testGroup "metadata"
+ [ testCompareWithOpts (def,def{readerStandalone=True})
+ "metadata fields"
+ "docx/metadata.native"
+ , testCompareWithOpts (def,def{readerStandalone=True})
+ "stop recording metadata with normal text"
+ "docx/metadata_after_normal.native"
+ ]
+
+ ]
diff --git a/tests/Tests/Writers/LaTeX.hs b/tests/Tests/Writers/LaTeX.hs
index 4d2d3fc05..d1cfd3ddf 100644
--- a/tests/Tests/Writers/LaTeX.hs
+++ b/tests/Tests/Writers/LaTeX.hs
@@ -42,7 +42,7 @@ tests = [ testGroup "code blocks"
, testGroup "definition lists"
[ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
[plain (text "hi there")])] =?>
- "\\begin{description}\n\\itemsep1pt\\parskip0pt\\parsep0pt\n\\item[{\\hyperref[go]{testing}}]\nhi there\n\\end{description}"
+ "\\begin{description}\n\\tightlist\n\\item[{\\hyperref[go]{testing}}]\nhi there\n\\end{description}"
]
, testGroup "math"
[ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
@@ -52,7 +52,7 @@ tests = [ testGroup "code blocks"
[ "unnumbered header" =:
headerWith ("foo",["unnumbered"],[]) 1
(text "Header 1" <> note (plain $ text "note")) =?>
- "\\section*{Header 1\\footnote{note}}\\label{foo}\n\\addcontentsline{toc}{section}{Header 1}\n"
+ "\\section*{\\texorpdfstring{Header 1\\footnote{note}}{Header 1}}\\label{foo}\n\\addcontentsline{toc}{section}{Header 1}\n"
, "in list item" =:
bulletList [header 2 (text "foo")] =?>
"\\begin{itemize}\n\\item ~\n \\subsection{foo}\n\\end{itemize}"
@@ -62,7 +62,7 @@ tests = [ testGroup "code blocks"
"\\begin{description}\n\\item[foo] ~ \n\\subsection{bar}\n\nbaz\n\\end{description}"
, "containing image" =:
header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
- "\\section{\\protect\\includegraphics{imgs/foo.jpg}}"
+ "\\section{\\texorpdfstring{\\protect\\includegraphics{imgs/foo.jpg}}{Alt text}}"
]
, testGroup "inline code"
[ "struck out and highlighted" =:
diff --git a/tests/Tests/Writers/Markdown.hs b/tests/Tests/Writers/Markdown.hs
index c2a8f5903..8ffd7a8c0 100644
--- a/tests/Tests/Writers/Markdown.hs
+++ b/tests/Tests/Writers/Markdown.hs
@@ -1,4 +1,5 @@
{-# LANGUAGE OverloadedStrings #-}
+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Tests.Writers.Markdown (tests) where
import Test.Framework
@@ -35,4 +36,92 @@ tests = [ "indented code after list"
=: bulletList [ plain "foo" <> bulletList [ plain "bar" ],
plain "baz" ]
=?> "- foo\n - bar\n- baz\n"
- ]
+ ] ++ [shortcutLinkRefsTests]
+
+shortcutLinkRefsTests :: Test
+shortcutLinkRefsTests =
+ let infix 4 =:
+ (=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> Test
+ (=:) = test (writeMarkdown (def {writerReferenceLinks = True}) . toPandoc)
+ in testGroup "Shortcut reference links"
+ [ "Simple link (shortcutable)"
+ =: (para (link "/url" "title" "foo"))
+ =?> "[foo]\n\n [foo]: /url \"title\""
+ , "Followed by another link (unshortcutable)"
+ =: (para ((link "/url1" "title1" "first")
+ <> (link "/url2" "title2" "second")))
+ =?> unlines [ "[first][][second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Followed by space and another link (unshortcutable)"
+ =: (para ((link "/url1" "title1" "first") <> " "
+ <> (link "/url2" "title2" "second")))
+ =?> unlines [ "[first][] [second]"
+ , ""
+ , " [first]: /url1 \"title1\""
+ , " [second]: /url2 \"title2\""
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: (para ((link "/url1" "" "foo") <> (link "/url2" "" "foo")
+ <> (link "/url3" "" "foo")))
+ =?> unlines [ "[foo][][foo][1][foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is used multiple times (unshortcutable)"
+ =: (para ((link "/url1" "" "foo") <> " " <> (link "/url2" "" "foo")
+ <> " " <> (link "/url3" "" "foo")))
+ =?> unlines [ "[foo][] [foo][1] [foo][2]"
+ , ""
+ , " [foo]: /url1"
+ , " [1]: /url2"
+ , " [2]: /url3"
+ ]
+ , "Reference link is followed by text in brackets"
+ =: (para ((link "/url" "" "link") <> "[text in brackets]"))
+ =?> unlines [ "[link][]\\[text in brackets\\]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and text in brackets"
+ =: (para ((link "/url" "" "link") <> " [text in brackets]"))
+ =?> unlines [ "[link][] \\[text in brackets\\]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline"
+ =: (para ((link "/url" "" "link") <> rawInline "markdown" "[rawText]"))
+ =?> unlines [ "[link][][rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and RawInline"
+ =: (para ((link "/url" "" "link") <> space <> rawInline "markdown" "[rawText]"))
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by RawInline with space"
+ =: (para ((link "/url" "" "link") <> rawInline "markdown" " [rawText]"))
+ =?> unlines [ "[link][] [rawText]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by citation"
+ =: (para ((link "/url" "" "link") <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
+ =?> unlines [ "[link][][@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ , "Reference link is followed by space and citation"
+ =: (para ((link "/url" "" "link") <> space <> cite [Citation "author" [] [] NormalCitation 0 0] (str "[@author]")))
+ =?> unlines [ "[link][] [@author]"
+ , ""
+ , " [link]: /url"
+ ]
+ ]
diff --git a/tests/Tests/Writers/RST.hs b/tests/Tests/Writers/RST.hs
new file mode 100644
index 000000000..2a511782f
--- /dev/null
+++ b/tests/Tests/Writers/RST.hs
@@ -0,0 +1,79 @@
+{-# LANGUAGE OverloadedStrings #-}
+module Tests.Writers.RST (tests) where
+
+import Test.Framework
+import Text.Pandoc.Builder
+import Text.Pandoc
+import Tests.Helpers
+import Tests.Arbitrary()
+
+infix 4 =:
+(=:) :: (ToString a, ToPandoc a)
+ => String -> (a, String) -> Test
+(=:) = test (writeRST def{ writerHighlight = True } . toPandoc)
+
+tests :: [Test]
+tests = [ testGroup "rubrics"
+ [ "in list item" =:
+ bulletList [header 2 (text "foo")] =?>
+ "- .. rubric:: foo"
+ , "in definition list item" =:
+ definitionList [(text "foo", [header 2 (text "bar"),
+ para $ text "baz"])] =?>
+ unlines
+ [ "foo"
+ , " .. rubric:: bar"
+ , ""
+ , " baz"]
+ , "in block quote" =:
+ blockQuote (header 1 (text "bar")) =?>
+ " .. rubric:: bar"
+ , "with id" =:
+ blockQuote (headerWith ("foo",[],[]) 1 (text "bar")) =?>
+ unlines
+ [ " .. rubric:: bar"
+ , " :name: foo"]
+ , "with id class" =:
+ blockQuote (headerWith ("foo",["baz"],[]) 1 (text "bar")) =?>
+ unlines
+ [ " .. rubric:: bar"
+ , " :name: foo"
+ , " :class: baz"]
+ ]
+ , testGroup "headings"
+ [ "normal heading" =:
+ header 1 (text "foo") =?>
+ unlines
+ [ "foo"
+ , "==="]
+ , "heading levels" =:
+ header 1 (text "Header 1") <>
+ header 3 (text "Header 2") <>
+ header 2 (text "Header 2") <>
+ header 1 (text "Header 1") <>
+ header 4 (text "Header 2") <>
+ header 5 (text "Header 3") <>
+ header 3 (text "Header 2") =?>
+ unlines
+ [ "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 1"
+ , "========"
+ , ""
+ , "Header 2"
+ , "--------"
+ , ""
+ , "Header 3"
+ , "~~~~~~~~"
+ , ""
+ , "Header 2"
+ , "--------"]
+ ]
+ ]
diff --git a/tests/docbook-reader.docbook b/tests/docbook-reader.docbook
index 9ba965d9b..3a4fc77c6 100644
--- a/tests/docbook-reader.docbook
+++ b/tests/docbook-reader.docbook
@@ -509,6 +509,25 @@ These should not be escaped: \$ \\ \&gt; \[ \{
B. Williams
</para>
</sect2>
+ <sect2 id="callout">
+ <title>Callout</title>
+ <para>Simple.</para>
+ <calloutlist>
+ <callout arearefs="loop1-letrec-co" id="loop1-letrec">
+ <para id="x_QA1">A <code>__letrec</code> is equivalent to a normal
+ Haskell &let;.</para>
+ </callout>
+ <callout arearefs="loop1-def-co" id="loop1-def">
+ <para id="x_RA1">&GHC; compiled the body of our list comprehension into
+ a loop named <function>go_s1YC</function>.</para>
+ </callout>
+ <callout arearefs="loop1-pat-empty-co" id="loop1-pat-empty">
+ <para id="x_SA1">If our &case; expression matches the empty list, we
+ return the empty list. This is reassuringly
+ familiar.</para>
+ </callout>
+ </calloutlist>
+ </sect2>
</sect1>
<sect1 id="definition-lists">
<title>Definition Lists</title>
@@ -691,6 +710,9 @@ These should not be escaped: \$ \\ \&gt; \[ \{
<literal>&lt;html&gt;</literal>.
</para>
<para>
+ More code: <classname>Class</classname> and <type>Type</type>
+ </para>
+ <para>
<emphasis role="strikethrough">This is
<emphasis>strikeout</emphasis>.</emphasis>
</para>
@@ -1011,12 +1033,12 @@ or here: &lt;http://example.com/&gt;
From <quote>Voyage dans la Lune</quote> by Georges Melies (1902):
</para>
<figure>
- <title>lalune</title>
+ <title>lalune fig caption</title>
<mediaobject>
<imageobject>
<imagedata fileref="lalune.jpg" />
</imageobject>
- <textobject><phrase>lalune</phrase></textobject>
+ <textobject><phrase>lalune alt text shadowed by fig caption</phrase></textobject>
</mediaobject>
</figure>
<para>
@@ -1025,7 +1047,25 @@ or here: &lt;http://example.com/&gt;
<imagedata fileref="movie.jpg" />
</imageobject>
</inlinemediaobject> icon.
+ And here a second movie <inlinemediaobject>
+ <alt>alt text</alt>
+ <imageobject>
+ <imagedata fileref="movie.jpg" />
+ </imageobject>
+ </inlinemediaobject> icon.
+ And here a third movie <inlinemediaobject>
+ <textobject><phrase>alt text</phrase></textobject>
+ <imageobject>
+ <imagedata fileref="movie.jpg" />
+ </imageobject>
+ </inlinemediaobject> icon.
</para>
+ <mediaobject>
+ <imageobject>
+ <imagedata fileref="lalune.jpg" />
+ </imageobject>
+ <textobject><phrase>lalune no figure alt text</phrase></textobject>
+ </mediaobject>
</sect1>
<sect1 id="footnotes">
<title>Footnotes</title>
diff --git a/tests/docbook-reader.native b/tests/docbook-reader.native
index 90d76b3c2..b87e28d1c 100644
--- a/tests/docbook-reader.native
+++ b/tests/docbook-reader.native
@@ -1,22 +1,22 @@
Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Space,Str "MacFarlane"],MetaInlines [Str "Anonymous"]]),("date",MetaInlines [Str "July",Space,Str "17,",Space,Str "2006"]),("title",MetaInlines [Str "Pandoc",Space,Str "Test",Space,Str "Suite"])]})
[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "set",Space,Str "of",Space,Str "tests",Space,Str "for",Space,Str "pandoc.",Space,Str "Most",Space,Str "of",Space,Str "them",Space,Str "are",Space,Str "adapted",Space,Str "from",Space,Str "John",Space,Str "Gruber\8217s",Space,Str "markdown",Space,Str "test",Space,Str "suite."]
-,Header 1 ("",[],[]) [Str "Headers"]
-,Header 2 ("",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
-,Header 3 ("",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 4 ("",[],[]) [Str "Level",Space,Str "4"]
-,Header 5 ("",[],[]) [Str "Level",Space,Str "5"]
+,Header 1 ("headers",[],[]) [Str "Headers"]
+,Header 2 ("level-2-with-an-embedded-link",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Str "an",Space,Link [Str "embedded",Space,Str "link"] ("/url","")]
+,Header 3 ("level-3-with-emphasis",[],[]) [Str "Level",Space,Str "3",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 4 ("level-4",[],[]) [Str "Level",Space,Str "4"]
+,Header 5 ("level-5",[],[]) [Str "Level",Space,Str "5"]
,Para [Str "Hi."]
-,Header 1 ("",[],[]) [Str "Level",Space,Str "1"]
-,Header 2 ("",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
-,Header 3 ("",[],[]) [Str "Level",Space,Str "3"]
+,Header 1 ("level-1",[],[]) [Str "Level",Space,Str "1"]
+,Header 2 ("level-2-with-emphasis",[],[]) [Str "Level",Space,Str "2",Space,Str "with",Space,Emph [Str "emphasis"]]
+,Header 3 ("level-3",[],[]) [Str "Level",Space,Str "3"]
,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 2 ("",[],[]) [Str "Level",Space,Str "2"]
+,Header 2 ("level-2",[],[]) [Str "Level",Space,Str "2"]
,Para [Str "with",Space,Str "no",Space,Str "blank",Space,Str "line"]
-,Header 1 ("",[],[]) [Str "Paragraphs"]
+,Header 1 ("paragraphs",[],[]) [Str "Paragraphs"]
,Para [Str "Here\8217s",Space,Str "a",Space,Str "regular",Space,Str "paragraph."]
,Para [Str "In",Space,Str "Markdown",Space,Str "1.0.0",Space,Str "and",Space,Str "earlier.",Space,Str "Version",Space,Str "8.",Space,Str "This",Space,Str "line",Space,Str "turns",Space,Str "into",Space,Str "a",Space,Str "list",Space,Str "item.",Space,Str "Because",Space,Str "a",Space,Str "hard-wrapped",Space,Str "line",Space,Str "in",Space,Str "the",Space,Str "middle",Space,Str "of",Space,Str "a",Space,Str "paragraph",Space,Str "looked",Space,Str "like",Space,Str "a",Space,Str "list",Space,Str "item."]
,Para [Str "Here\8217s",Space,Str "one",Space,Str "with",Space,Str "a",Space,Str "bullet.",Space,Str "*",Space,Str "criminey."]
-,Header 1 ("",[],[]) [Str "Block",Space,Str "Quotes"]
+,Header 1 ("block-quotes",[],[]) [Str "Block",Space,Str "Quotes"]
,Para [Str "E-mail",Space,Str "style:"]
,BlockQuote
[Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote.",Space,Str "It",Space,Str "is",Space,Str "pretty",Space,Str "short."]]
@@ -35,13 +35,13 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
[Para [Str "nested"]]]
,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "block",Space,Str "quote:",Space,Str "2",Space,Str ">",Space,Str "1."]
,Para [Str "And",Space,Str "a",Space,Str "following",Space,Str "paragraph."]
-,Header 1 ("",[],[]) [Str "Code",Space,Str "Blocks"]
+,Header 1 ("code-blocks",[],[]) [Str "Code",Space,Str "Blocks"]
,Para [Str "Code:"]
,CodeBlock ("",[],[]) "---- (should be four hyphens)\n\nsub status {\n print \"working\";\n}\n\nthis code block is indented by one tab"
,Para [Str "And:"]
,CodeBlock ("",[],[]) " this code block is indented by two tabs\n\nThese should not be escaped: \\$ \\\\ \\> \\[ \\{"
-,Header 1 ("",[],[]) [Str "Lists"]
-,Header 2 ("",[],[]) [Str "Unordered"]
+,Header 1 ("lists",[],[]) [Str "Lists"]
+,Header 2 ("unordered",[],[]) [Str "Unordered"]
,Para [Str "Asterisks",Space,Str "loose:"]
,BulletList
[[Para [Str "asterisk",Space,Str "1"]]
@@ -57,7 +57,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
[[Para [Str "Minus",Space,Str "1"]]
,[Para [Str "Minus",Space,Str "2"]]
,[Para [Str "Minus",Space,Str "3"]]]
-,Header 2 ("",[],[]) [Str "Ordered"]
+,Header 2 ("ordered",[],[]) [Str "Ordered"]
,OrderedList (1,Decimal,DefaultDelim)
[[Para [Str "First"]]
,[Para [Str "Second"]]
@@ -73,7 +73,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Str "Item",Space,Str "1.",Space,Str "graf",Space,Str "two.",Space,Str "The",Space,Str "quick",Space,Str "brown",Space,Str "fox",Space,Str "jumped",Space,Str "over",Space,Str "the",Space,Str "lazy",Space,Str "dog\8217s",Space,Str "back."]]
,[Para [Str "Item",Space,Str "2."]]
,[Para [Str "Item",Space,Str "3."]]]
-,Header 2 ("",[],[]) [Str "Nested"]
+,Header 2 ("nested",[],[]) [Str "Nested"]
,BulletList
[[Para [Str "Tab"]
,BulletList
@@ -98,14 +98,14 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,[Para [Str "Fie"]]
,[Para [Str "Foe"]]]]
,[Para [Str "Third"]]]
-,Header 2 ("",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
+,Header 2 ("tabs-and-spaces",[],[]) [Str "Tabs",Space,Str "and",Space,Str "spaces"]
,BulletList
[[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
,[Para [Str "this",Space,Str "is",Space,Str "a",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]
,BulletList
[[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "tabs"]]
,[Para [Str "this",Space,Str "is",Space,Str "an",Space,Str "example",Space,Str "list",Space,Str "item",Space,Str "indented",Space,Str "with",Space,Str "spaces"]]]]]
-,Header 2 ("",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
+,Header 2 ("fancy-list-markers",[],[]) [Str "Fancy",Space,Str "list",Space,Str "markers"]
,OrderedList (2,Decimal,DefaultDelim)
[[Para [Str "begins",Space,Str "with",Space,Str "2"]]
,[Para [Str "and",Space,Str "now",Space,Str "3"]
@@ -134,7 +134,13 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Str "Should",Space,Str "not",Space,Str "be",Space,Str "a",Space,Str "list",Space,Str "item:"]
,Para [Str "M.A.\160\&2007"]
,Para [Str "B.",Space,Str "Williams"]
-,Header 1 ("",[],[]) [Str "Definition",Space,Str "Lists"]
+,Header 2 ("callout",[],[]) [Str "Callout"]
+,Para [Str "Simple."]
+,BulletList
+ [[Para [Str "A",Space,Code ("",[],[]) "__letrec",Space,Str "is",Space,Str "equivalent",Space,Str "to",Space,Str "a",Space,Str "normal",Space,Str "Haskell",Space,Str "LET."]]
+ ,[Para [Str "GHC",Space,Str "compiled",Space,Str "the",Space,Str "body",Space,Str "of",Space,Str "our",Space,Str "list",Space,Str "comprehension",Space,Str "into",Space,Str "a",Space,Str "loop",Space,Str "named",Space,Code ("",[],[]) "go_s1YC",Str "."]]
+ ,[Para [Str "If",Space,Str "our",Space,Str "CASE",Space,Str "expression",Space,Str "matches",Space,Str "the",Space,Str "empty",Space,Str "list,",Space,Str "we",Space,Str "return",Space,Str "the",Space,Str "empty",Space,Str "list.",Space,Str "This",Space,Str "is",Space,Str "reassuringly",Space,Str "familiar."]]]
+,Header 1 ("definition-lists",[],[]) [Str "Definition",Space,Str "Lists"]
,DefinitionList
[([Str "apple"],
[[Para [Str "red",Space,Str "fruit"]]])
@@ -170,7 +176,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,OrderedList (1,Decimal,DefaultDelim)
[[Para [Str "sublist"]]
,[Para [Str "sublist"]]]]])]
-,Header 1 ("",[],[]) [Str "Inline",Space,Str "Markup"]
+,Header 1 ("inline-markup",[],[]) [Str "Inline",Space,Str "Markup"]
,Para [Str "This",Space,Str "is",Space,Emph [Str "emphasized"],Str ",",Space,Str "and",Space,Str "so",Space,Emph [Str "is",Space,Str "this"],Str "."]
,Para [Str "This",Space,Str "is",Space,Strong [Str "strong"],Str ",",Space,Str "and",Space,Str "so",Space,Strong [Str "is",Space,Str "this"],Str "."]
,Para [Str "An",Space,Emph [Link [Str "emphasized",Space,Str "link"] ("/url","")],Str "."]
@@ -179,20 +185,21 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Strong [Emph [Str "This",Space,Str "is",Space,Str "strong",Space,Str "and",Space,Str "em."]]]
,Para [Str "So",Space,Str "is",Space,Strong [Emph [Str "this"]],Space,Str "word."]
,Para [Str "This",Space,Str "is",Space,Str "code:",Space,Code ("",[],[]) ">",Str ",",Space,Code ("",[],[]) "$",Str ",",Space,Code ("",[],[]) "\\",Str ",",Space,Code ("",[],[]) "\\$",Str ",",Space,Code ("",[],[]) "<html>",Str "."]
+,Para [Str "More",Space,Str "code:",Space,Code ("",[],[]) "Class",Space,Str "and",Space,Code ("",[],[]) "Type"]
,Para [Strikeout [Str "This",Space,Str "is",Space,Emph [Str "strikeout"],Str "."]]
,Para [Str "Superscripts:",Space,Str "a",Superscript [Str "bc"],Str "d",Space,Str "a",Superscript [Emph [Str "hello"]],Space,Str "a",Superscript [Str "hello\160there"],Str "."]
,Para [Str "Subscripts:",Space,Str "H",Subscript [Str "2"],Str "O,",Space,Str "H",Subscript [Str "23"],Str "O,",Space,Str "H",Subscript [Str "many\160of\160them"],Str "O."]
,Para [Str "These",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "superscripts",Space,Str "or",Space,Str "subscripts,",Space,Str "because",Space,Str "of",Space,Str "the",Space,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a~b",Space,Str "c~d."]
-,Header 1 ("",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
+,Header 1 ("smart-quotes-ellipses-dashes",[],[]) [Str "Smart",Space,Str "quotes,",Space,Str "ellipses,",Space,Str "dashes"]
,Para [Quoted DoubleQuote [Str "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
,Para [Quoted DoubleQuote [Str "A"],Str ",",Space,Quoted DoubleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted DoubleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
,Para [Quoted DoubleQuote [Str "He",Space,Str "said,",Space,Quoted SingleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."]],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70\8217s?"]
,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two",Space,Str "\8212",Space,Str "three\8212four",Space,Str "\8212",Space,Str "five."]
,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
,Para [Str "Ellipses\8230and\8230and\8230."]
-,Header 1 ("",[],[]) []
+,Header 1 ("math",[],[]) []
,Para [Math DisplayMath "e = mc^{2}",Math DisplayMath "1",Space,Math InlineMath "e = mc^{2}",Space,Math DisplayMath "e = mc^{2}"]
-,Header 1 ("",[],[]) [Str "Special",Space,Str "Characters"]
+,Header 1 ("special-characters",[],[]) [Str "Special",Space,Str "Characters"]
,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "unicode:"]
,BulletList
[[Para [Str "I",Space,Str "hat:",Space,Str "\206"]]
@@ -221,8 +228,8 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Str "Bang:",Space,Str "!"]
,Para [Str "Plus:",Space,Str "+"]
,Para [Str "Minus:",Space,Str "-"]
-,Header 1 ("",[],[]) [Str "Links"]
-,Header 2 ("",[],[]) [Str "Explicit"]
+,Header 1 ("links",[],[]) [Str "Links"]
+,Header 2 ("explicit",[],[]) [Str "Explicit"]
,Para [Str "Just",Space,Str "a",Space,Link [Str "URL"] ("/url/",""),Str "."]
,Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
,Para [Link [Str "URL",Space,Str "and",Space,Str "title"] ("/url/",""),Str "."]
@@ -232,7 +239,7 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Link [Str "with_underscore"] ("/url/with_underscore","")]
,Para [Link [Str "nobody@nowhere.net"] ("mailto:nobody@nowhere.net","")]
,Para [Link [Str "Empty"] ("",""),Str "."]
-,Header 2 ("",[],[]) [Str "Reference"]
+,Header 2 ("reference",[],[]) [Str "Reference"]
,Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
,Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
,Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
@@ -245,12 +252,12 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,CodeBlock ("",[],[]) "[not]: /url"
,Para [Str "Foo",Space,Link [Str "bar"] ("/url/",""),Str "."]
,Para [Str "Foo",Space,Link [Str "biz"] ("/url/",""),Str "."]
-,Header 2 ("",[],[]) [Str "With",Space,Str "ampersands"]
+,Header 2 ("with-ampersands",[],[]) [Str "With",Space,Str "ampersands"]
,Para [Str "Here\8217s",Space,Str "a",Space,Link [Str "link",Space,Str "with",Space,Str "an",Space,Str "ampersand",Space,Str "in",Space,Str "the",Space,Str "URL"] ("http://example.com/?foo=1&bar=2",""),Str "."]
,Para [Str "Here\8217s",Space,Str "a",Space,Str "link",Space,Str "with",Space,Str "an",Space,Str "amersand",Space,Str "in",Space,Str "the",Space,Str "link",Space,Str "text:",Space,Link [Str "AT&T"] ("http://att.com/",""),Str "."]
,Para [Str "Here\8217s",Space,Str "an",Space,Link [Str "inline",Space,Str "link"] ("/script?foo=1&bar=2",""),Str "."]
,Para [Str "Here\8217s",Space,Str "an",Space,Link [Str "inline",Space,Str "link",Space,Str "in",Space,Str "pointy",Space,Str "braces"] ("/script?foo=1&bar=2",""),Str "."]
-,Header 2 ("",[],[]) [Str "Autolinks"]
+,Header 2 ("autolinks",[],[]) [Str "Autolinks"]
,Para [Str "With",Space,Str "an",Space,Str "ampersand:",Space,Link [Str "http://example.com/?foo=1&bar=2"] ("http://example.com/?foo=1&bar=2","")]
,BulletList
[[Para [Str "In",Space,Str "a",Space,Str "list?"]]
@@ -261,18 +268,19 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
[Para [Str "Blockquoted:",Space,Link [Str "http://example.com/"] ("http://example.com/","")]]
,Para [Str "Auto-links",Space,Str "should",Space,Str "not",Space,Str "occur",Space,Str "here:",Space,Code ("",[],[]) "<http://example.com/>"]
,CodeBlock ("",[],[]) "or here: <http://example.com/>"
-,Header 1 ("",[],[]) [Str "Images"]
+,Header 1 ("images",[],[]) [Str "Images"]
,Para [Str "From",Space,Quoted DoubleQuote [Str "Voyage",Space,Str "dans",Space,Str "la",Space,Str "Lune"],Space,Str "by",Space,Str "Georges",Space,Str "Melies",Space,Str "(1902):"]
-,Para [Image [Str "lalune"] ("lalune.jpg","")]
-,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [] ("movie.jpg",""),Space,Str "icon."]
-,Header 1 ("",[],[]) [Str "Footnotes"]
+,Para [Image [Str "lalune",Space,Str "fig",Space,Str "caption"] ("lalune.jpg","fig:")]
+,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "movie",Space,Image [] ("movie.jpg",""),Space,Str "icon.",Space,Str "And",Space,Str "here",Space,Str "a",Space,Str "second",Space,Str "movie",Space,Image [Str "alt",Space,Str "text"] ("movie.jpg",""),Space,Str "icon.",Space,Str "And",Space,Str "here",Space,Str "a",Space,Str "third",Space,Str "movie",Space,Image [Str "alt",Space,Str "text"] ("movie.jpg",""),Space,Str "icon."]
+,Para [Image [Str "lalune",Space,Str "no",Space,Str "figure",Space,Str "alt",Space,Str "text"] ("lalune.jpg","")]
+,Header 1 ("footnotes",[],[]) [Str "Footnotes"]
,Para [Str "Here",Space,Str "is",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Note [Para [Str "Here",Space,Str "is",Space,Str "the",Space,Str "footnote.",Space,Str "It",Space,Str "can",Space,Str "go",Space,Str "anywhere",Space,Str "after",Space,Str "the",Space,Str "footnote",Space,Str "reference.",Space,Str "It",Space,Str "need",Space,Str "not",Space,Str "be",Space,Str "placed",Space,Str "at",Space,Str "the",Space,Str "end",Space,Str "of",Space,Str "the",Space,Str "document."]],Space,Str "and",Space,Str "another.",Note [Para [Str "Here\8217s",Space,Str "the",Space,Str "long",Space,Str "note.",Space,Str "This",Space,Str "one",Space,Str "contains",Space,Str "multiple",Space,Str "blocks."],Para [Str "Subsequent",Space,Str "blocks",Space,Str "are",Space,Str "indented",Space,Str "to",Space,Str "show",Space,Str "that",Space,Str "they",Space,Str "belong",Space,Str "to",Space,Str "the",Space,Str "footnote",Space,Str "(as",Space,Str "with",Space,Str "list",Space,Str "items)."],CodeBlock ("",[],[]) " { <code> }",Para [Str "If",Space,Str "you",Space,Str "want,",Space,Str "you",Space,Str "can",Space,Str "indent",Space,Str "every",Space,Str "line,",Space,Str "but",Space,Str "you",Space,Str "can",Space,Str "also",Space,Str "be",Space,Str "lazy",Space,Str "and",Space,Str "just",Space,Str "indent",Space,Str "the",Space,Str "first",Space,Str "line",Space,Str "of",Space,Str "each",Space,Str "block."]],Space,Str "This",Space,Str "should",Space,Emph [Str "not"],Space,Str "be",Space,Str "a",Space,Str "footnote",Space,Str "reference,",Space,Str "because",Space,Str "it",Space,Str "contains",Space,Str "a",Space,Str "space.[^my",Space,Str "note]",Space,Str "Here",Space,Str "is",Space,Str "an",Space,Str "inline",Space,Str "note.",Note [Para [Str "This",Space,Str "is",Space,Emph [Str "easier"],Space,Str "to",Space,Str "type.",Space,Str "Inline",Space,Str "notes",Space,Str "may",Space,Str "contain",Space,Link [Str "links"] ("http://google.com",""),Space,Str "and",Space,Code ("",[],[]) "]",Space,Str "verbatim",Space,Str "characters,",Space,Str "as",Space,Str "well",Space,Str "as",Space,Str "[bracketed",Space,Str "text]."]]]
,BlockQuote
[Para [Str "Notes",Space,Str "can",Space,Str "go",Space,Str "in",Space,Str "quotes.",Note [Para [Str "In",Space,Str "quote."]]]]
,OrderedList (1,Decimal,DefaultDelim)
[[Para [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]
-,Header 1 ("",[],[]) [Str "Tables"]
+,Header 1 ("tables",[],[]) [Str "Tables"]
,Para [Str "Simple",Space,Str "table",Space,Str "with",Space,Str "caption:"]
,Table [Str "Demonstration",Space,Str "of",Space,Str "simple",Space,Str "table",Space,Str "syntax."] [AlignRight,AlignLeft,AlignCenter,AlignLeft] [0.0,0.0,0.0,0.0]
[[Plain [Str "Right"]]
diff --git a/tests/docx/danish_headers.docx b/tests/docx/danish_headers.docx
deleted file mode 100644
index 345fc632c..000000000
--- a/tests/docx/danish_headers.docx
+++ /dev/null
Binary files differ
diff --git a/tests/docx/danish_headers.native b/tests/docx/danish_headers.native
deleted file mode 100644
index 12a857811..000000000
--- a/tests/docx/danish_headers.native
+++ /dev/null
@@ -1,10 +0,0 @@
-[Header 1 ("testoverskrift",[],[]) [Str "Testoverskrift"]
-,Para [Str "Normal"]
-,Header 2 ("testoverskrift-2",[],[]) [Str "Testoverskrift",Space,Str "2"]
-,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
- [[Plain [Str "Kolonne1"]]
- ,[Plain [Str "Kolonne2"]]]
- [[[Plain [Str "Testdata",Space,Str "1"]]
- ,[Plain [Str "Tester2"]]]
- ,[[Plain [Str "Testdata",Space,Str "2"]]
- ,[Plain [Str "Tester3"]]]]]
diff --git a/tests/docx/german_styled_lists.docx b/tests/docx/german_styled_lists.docx
new file mode 100644
index 000000000..ce454e9cc
--- /dev/null
+++ b/tests/docx/german_styled_lists.docx
Binary files differ
diff --git a/tests/docx/german_styled_lists.native b/tests/docx/german_styled_lists.native
new file mode 100644
index 000000000..4d5456dfc
--- /dev/null
+++ b/tests/docx/german_styled_lists.native
@@ -0,0 +1,6 @@
+[BulletList
+ [[Para [Str "One",Space,Str "level",Space,Str "of",Space,Str "the",Space,Str "list."]]
+ ,[Para [Str "Second",Space,Str "level",Space,Str "of",Space,Str "the",Space,Str "list."]
+ ,BulletList
+ [[Para [Str "Next",Space,Str "level",Space,Str "of",Space,Str "the",Space,Str "list"]]]]
+ ,[Para [Str "Back",Space,Str "to",Space,Str "the",Space,Str "top",Space,Str "level."]]]]
diff --git a/tests/docx/headers.docx b/tests/docx/headers.docx
index 630b6bfc5..e1fbbcc75 100644
--- a/tests/docx/headers.docx
+++ b/tests/docx/headers.docx
Binary files differ
diff --git a/tests/docx/headers.native b/tests/docx/headers.native
index 03f967728..5d0065239 100644
--- a/tests/docx/headers.native
+++ b/tests/docx/headers.native
@@ -2,4 +2,12 @@
,Header 2 ("second-level",[],[]) [Str "Second",Space,Str "Level"]
,Para [Str "Some",Space,Str "plain",Space,Str "text."]
,Header 3 ("third-level",[],[]) [Str "Third",Space,Str "level"]
-,Para [Str "Some",Space,Str "more",Space,Str "plain",Space,Str "text."]]
+,Para [Str "Some",Space,Str "more",Space,Str "plain",Space,Str "text."]
+,Header 4 ("fourth-level",[],[]) [Str "Fourth",Space,Str "level"]
+,Para [Str "Some",Space,Str "more",Space,Str "plain",Space,Str "text."]
+,Header 5 ("fifth-level",[],[]) [Str "Fifth",Space,Str "level"]
+,Para [Str "Some",Space,Str "more",Space,Str "plain",Space,Str "text."]
+,Header 6 ("sixth-level",[],[]) [Str "Sixth",Space,Str "level"]
+,Para [Str "Some",Space,Str "more",Space,Str "plain",Space,Str "text."]
+,Para [Str "Seventh",Space,Str "level"]
+,Para [Str "Since",Space,Str "no",Space,Str "Heading",Space,Str "7",Space,Str "style",Space,Str "exists",Space,Str "in",Space,Str "styles.xml,",Space,Str "this",Space,Str "gets",Space,Str "converted",Space,Str "to",Space,Str "Span."]]
diff --git a/tests/docx/i18n_blocks.docx b/tests/docx/i18n_blocks.docx
new file mode 100644
index 000000000..36341c363
--- /dev/null
+++ b/tests/docx/i18n_blocks.docx
Binary files differ
diff --git a/tests/docx/i18n_blocks.native b/tests/docx/i18n_blocks.native
new file mode 100644
index 000000000..582a7360d
--- /dev/null
+++ b/tests/docx/i18n_blocks.native
@@ -0,0 +1,8 @@
+[Header 1 ("this-is-heading-1",[],[]) [Str "This",Space,Str "is",Space,Str "Heading",Space,Str "1"]
+,Header 2 ("this-is-heading-2",[],[]) [Str "This",Space,Str "is",Space,Str "Heading",Space,Str "2"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "Quote"]
+ ,Para [Str "This",Space,Str "is",Space,Str "Block",Space,Str "Text"]]
+,BulletList
+ [[Para [Str "This",Space,Str "is",Space,Str "list",Space,Str "item",Space,Str "1"]]
+ ,[Para [Str "This",Space,Str "is",Space,Str "list",Space,Str "item",Space,Str "2"]]]]
diff --git a/tests/docx/image_no_embed_writer.native b/tests/docx/image_no_embed_writer.native
new file mode 100644
index 000000000..21802ebd1
--- /dev/null
+++ b/tests/docx/image_no_embed_writer.native
@@ -0,0 +1,2 @@
+[Para [Str "An",Space,Str "image:"]
+,Para [Image [] ("media/rId25.jpg","")]]
diff --git a/tests/docx/image_vml.docx b/tests/docx/image_vml.docx
new file mode 100644
index 000000000..9e4018e00
--- /dev/null
+++ b/tests/docx/image_vml.docx
Binary files differ
diff --git a/tests/docx/image_vml.native b/tests/docx/image_vml.native
new file mode 100644
index 000000000..8c5450a19
--- /dev/null
+++ b/tests/docx/image_vml.native
@@ -0,0 +1,4 @@
+[Header 1 ("vml-image",[],[]) [Strong [Str "VML",Space,Str "Image"]]
+,BlockQuote
+ [Para [Str "It",Space,Str "should",Space,Str "follow",Space,Str "below:"]
+ ,Para [Image [] ("media/image4.jpeg","")]]]
diff --git a/tests/docx/inline_formatting_writer.native b/tests/docx/inline_formatting_writer.native
new file mode 100644
index 000000000..be346204e
--- /dev/null
+++ b/tests/docx/inline_formatting_writer.native
@@ -0,0 +1,5 @@
+[Para [Str "Regular",Space,Str "text",Space,Emph [Str "italics"],Space,Strong [Str "bold",Space,Emph [Str "bold",Space,Str "italics"]],Str "."]
+,Para [Str "This",Space,Str "is",Space,SmallCaps [Str "Small",Space,Str "Caps"],Str ",",Space,Str "and",Space,Str "this",Space,Str "is",Space,Strikeout [Str "strikethrough"],Str "."]
+,Para [Str "Some",Space,Str "people",Space,Str "use",Space,Emph [Str "single",Space,Str "underlines",Space,Str "for",Space,Str "emphasis"],Str "."]
+,Para [Str "Above",Space,Str "the",Space,Str "line",Space,Str "is",Space,Superscript [Str "superscript"],Space,Str "and",Space,Str "below",Space,Str "the",Space,Str "line",Space,Str "is",Space,Subscript [Str "subscript"],Str "."]
+,Para [Str "A",Space,Str "line",LineBreak,Str "break."]]
diff --git a/tests/docx/inline_images_writer.native b/tests/docx/inline_images_writer.native
new file mode 100644
index 000000000..da2a2709b
--- /dev/null
+++ b/tests/docx/inline_images_writer.native
@@ -0,0 +1,2 @@
+[Para [Str "This",Space,Str "picture",Space,Image [] ("media/rId26.jpg",""),Space,Str "is",Space,Str "an",Space,Str "identicon."]
+,Para [Str "Here",Space,Str "is",Space,Link [Str "one",Space,Image [] ("media/rId27.jpg",""),Space,Str "that"] ("http://www.google.com",""),Space,Str "links."]]
diff --git a/tests/docx/links.docx b/tests/docx/links.docx
index 10ec62fd7..80fecacaf 100644
--- a/tests/docx/links.docx
+++ b/tests/docx/links.docx
Binary files differ
diff --git a/tests/docx/links.native b/tests/docx/links.native
index c741fe875..a05578100 100644
--- a/tests/docx/links.native
+++ b/tests/docx/links.native
@@ -1,5 +1,6 @@
[Header 2 ("an-internal-link-and-an-external-link",[],[]) [Str "An",Space,Str "internal",Space,Str "link",Space,Str "and",Space,Str "an",Space,Str "external",Space,Str "link"]
,Para [Str "An",Space,Link [Str "external",Space,Str "link"] ("http://google.com",""),Space,Str "to",Space,Str "a",Space,Str "popular",Space,Str "website."]
+,Para [Str "An",Space,Link [Str "external",Space,Str "link"] ("http://pandoc.org/README.html#synopsis",""),Space,Str "to",Space,Str "a",Space,Str "website",Space,Str "with",Space,Str "an",Space,Str "anchor."]
,Para [Str "An",Space,Link [Str "internal",Space,Str "link"] ("#a-section-for-testing-link-targets",""),Space,Str "to",Space,Str "a",Space,Str "section",Space,Str "header."]
,Para [Str "An",Space,Link [Str "internal",Space,Str "link"] ("#my_bookmark",""),Space,Str "to",Space,Str "a",Space,Str "bookmark."]
,Header 2 ("a-section-for-testing-link-targets",[],[]) [Str "A",Space,Str "section",Space,Str "for",Space,Str "testing",Space,Str "link",Space,Str "targets"]
diff --git a/tests/docx/links_writer.native b/tests/docx/links_writer.native
new file mode 100644
index 000000000..25f4f90f9
--- /dev/null
+++ b/tests/docx/links_writer.native
@@ -0,0 +1,6 @@
+[Header 2 ("an-internal-link-and-an-external-link",[],[]) [Str "An",Space,Str "internal",Space,Str "link",Space,Str "and",Space,Str "an",Space,Str "external",Space,Str "link"]
+,Para [Str "An",Space,Link [Str "external",Space,Str "link"] ("http://google.com",""),Space,Str "to",Space,Str "a",Space,Str "popular",Space,Str "website."]
+,Para [Str "An",Space,Link [Str "external",Space,Str "link"] ("http://pandoc.org/README.html#synopsis",""),Space,Str "to",Space,Str "a",Space,Str "website",Space,Str "with",Space,Str "an",Space,Str "anchor."]
+,Para [Str "An",Space,Link [Str "internal",Space,Str "link"] ("#a-section-for-testing-link-targets",""),Space,Str "to",Space,Str "a",Space,Str "section",Space,Str "header."]
+,Para [Str "An",Space,Link [Str "internal",Space,Str "link"] ("#my_bookmark",""),Space,Str "to",Space,Str "a",Space,Str "bookmark."]
+,Header 2 ("a-section-for-testing-link-targets",[],[]) [Str "A",Space,Str "section",Space,Str "for",Space,Str "testing",Space,Str "link",Space,Str "targets"]]
diff --git a/tests/docx/lists_writer.native b/tests/docx/lists_writer.native
new file mode 100644
index 000000000..4c44ea603
--- /dev/null
+++ b/tests/docx/lists_writer.native
@@ -0,0 +1,17 @@
+[Header 2 ("some-nested-lists",[],[]) [Str "Some",Space,Str "nested",Space,Str "lists"]
+,OrderedList (1,Decimal,Period)
+ [[Para [Str "one"]]
+ ,[Para [Str "two"]
+ ,OrderedList (1,LowerAlpha,DefaultDelim)
+ [[Para [Str "a"]]
+ ,[Para [Str "b"]]]]]
+,BulletList
+ [[Para [Str "one"]]
+ ,[Para [Str "two"]
+ ,BulletList
+ [[Para [Str "three"]
+ ,BulletList
+ [[Para [Str "four"]]]]]]
+ ,[Para [Str "Same",Space,Str "list"]]]
+,BulletList
+ [[Para [Str "Different",Space,Str "list",Space,Str "adjacent",Space,Str "to",Space,Str "the",Space,Str "one",Space,Str "above."]]]]
diff --git a/tests/docx/table_with_list_cell.docx b/tests/docx/table_with_list_cell.docx
new file mode 100644
index 000000000..1db065770
--- /dev/null
+++ b/tests/docx/table_with_list_cell.docx
Binary files differ
diff --git a/tests/docx/table_with_list_cell.native b/tests/docx/table_with_list_cell.native
new file mode 100644
index 000000000..81bb15a1e
--- /dev/null
+++ b/tests/docx/table_with_list_cell.native
@@ -0,0 +1,11 @@
+[Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "Cell",Space,Str "with",Space,Str "text"]]
+ ,[Plain [Str "Cell",Space,Str "with",Space,Str "text"]]]
+ [[[BulletList
+ [[Para [Str "Cell",Space,Str "with"]]
+ ,[Para [Str "A"]]
+ ,[Para [Str "Bullet",Space,Str "list"]]]]
+ ,[OrderedList (1,Decimal,Period)
+ [[Para [Str "Cell",Space,Str "with"]]
+ ,[Para [Str "A"]]
+ ,[Para [Str "Numbered",Space,Str "list."]]]]]]]
diff --git a/tests/docx/verbatim_subsuper.docx b/tests/docx/verbatim_subsuper.docx
new file mode 100644
index 000000000..2cb0dc16d
--- /dev/null
+++ b/tests/docx/verbatim_subsuper.docx
Binary files differ
diff --git a/tests/docx/verbatim_subsuper.native b/tests/docx/verbatim_subsuper.native
new file mode 100644
index 000000000..2e11e646a
--- /dev/null
+++ b/tests/docx/verbatim_subsuper.native
@@ -0,0 +1,8 @@
+[Para [Str "m",Superscript [Str "2"]]
+,Para [Str "m",Superscript [Code ("",[],[]) "2"]]
+,Para [Code ("",[],[]) "m",Superscript [Str "2"]]
+,Para [Code ("",[],[]) "m",Superscript [Code ("",[],[]) "2"]]
+,Para [Str "m",Subscript [Str "2"]]
+,Para [Str "m",Subscript [Code ("",[],[]) "2"]]
+,Para [Code ("",[],[]) "m",Subscript [Str "2"]]
+,Para [Code ("",[],[]) "m",Subscript [Code ("",[],[]) "2"]]]
diff --git a/tests/dokuwiki_external_images.dokuwiki b/tests/dokuwiki_external_images.dokuwiki
new file mode 100644
index 000000000..cc7eddcda
--- /dev/null
+++ b/tests/dokuwiki_external_images.dokuwiki
@@ -0,0 +1 @@
+{{https://cooluri.com/image.png|HTTPS image}} {{http://cooluri.com/image.png|HTTP image}} {{ftp://ftp.cooluri.com/image.png|FTP image}} {{file:///tmp/coolimage.png|Filesystem image}} {{:/image.jpg|Relative image 1}} {{:image.jpg|Relative image 2}}
diff --git a/tests/dokuwiki_external_images.native b/tests/dokuwiki_external_images.native
new file mode 100644
index 000000000..c2b8876d3
--- /dev/null
+++ b/tests/dokuwiki_external_images.native
@@ -0,0 +1 @@
+[Para [Image [Str "HTTPS",Space,Str "image"] ("https://cooluri.com/image.png",""),Space,Image [Str "HTTP",Space,Str "image"] ("http://cooluri.com/image.png",""),Space,Image [Str "FTP",Space,Str "image"] ("ftp://ftp.cooluri.com/image.png",""),Space,Image [Str "Filesystem",Space,Str "image"] ("file:///tmp/coolimage.png",""),Space,Image [Str "Relative",Space,Str "image",Space,Str "1"] ("/image.jpg",""),Space,Image [Str "Relative",Space,Str "image",Space,Str "2"] ("image.jpg","")]]
diff --git a/tests/dokuwiki_inline_formatting.dokuwiki b/tests/dokuwiki_inline_formatting.dokuwiki
index dd5cb52b4..262094184 100644
--- a/tests/dokuwiki_inline_formatting.dokuwiki
+++ b/tests/dokuwiki_inline_formatting.dokuwiki
@@ -6,7 +6,8 @@ Some people use single underlines for //emphasis//.
Above the line is <sup>superscript</sup> and below the line is <sub>subscript</sub>.
-A line\\ break.
+A line\\
+break.
hello %%//%% world %%**%% from %%__%% me
diff --git a/tests/html-reader.html b/tests/html-reader.html
index 14ad3ed54..b6dd50fcc 100644
--- a/tests/html-reader.html
+++ b/tests/html-reader.html
@@ -259,13 +259,13 @@ These should not be escaped: \$ \\ \> \[ \{
></ol
><p
>Nesting:</p
- ><ol class="upper-alpha"
+ ><ol type="A"
><li
>Upper Alpha<ol class="upper-roman"
><li
>Upper Roman.<ol start="6" class="decimal"
><li
- >Decimal start with 6<ol start="3" class="lower-alpha"
+ >Decimal start with 6<ol start="3" type="a"
><li
>Lower alpha with paren</li
></ol
@@ -433,6 +433,7 @@ An e-mail address: nobody [at] nowhere.net<blockquote>
<p>text<em> Leading spaces</em></p>
<p><em>Trailing spaces </em>text</p>
<h1>Tables</h1>
+<h2>Tables with Headers</h2>
<table>
<tr>
<th>X</th>
@@ -450,6 +451,251 @@ An e-mail address: nobody [at] nowhere.net<blockquote>
<td>6</td>
</tr>
</table>
-</body>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>1</th>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <th>4</th>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <th>1</th>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <th>4</th>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tfoot>
+</table>
+<hr />
+<table>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <th>1</th>
+ <th>2</th>
+ <th>3</th>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+</table>
+<hr />
+<table>
+ <tbody>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ </thead>
+ <tbody>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <thead>
+ <tr>
+ <th>X</th>
+ <th>Y</th>
+ <th>Z</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td><p>2</p></td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tbody>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<h2>Tables without Headers</h2>
+<table>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+</table>
+<hr />
+<table>
+ <thead>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tbody>
+</table>
+<hr />
+<table>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>2</td>
+ <td>3</td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <tr>
+ <td>4</td>
+ <td>5</td>
+ <td>6</td>
+ </tr>
+ </tfoot>
+</table>
+<h2>Empty Tables</h2>
+<p>This section should be empty.</p>
+<table>
+ <tbody>
+ </tbody>
+</table>
+<table>
+</table>
</body>
</html>
diff --git a/tests/html-reader.native b/tests/html-reader.native
index aef6e40fc..b2d660fda 100644
--- a/tests/html-reader.native
+++ b/tests/html-reader.native
@@ -311,6 +311,7 @@ Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("titl
,Para [Str "text",Space,Emph [Str "Leading",Space,Str "spaces"]]
,Para [Emph [Str "Trailing",Space,Str "spaces"],Space,Str "text"]
,Header 1 ("",[],[]) [Str "Tables"]
+,Header 2 ("",[],[]) [Str "Tables",Space,Str "with",Space,Str "Headers"]
,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
[[Plain [Str "X"]]
,[Plain [Str "Y"]]
@@ -320,4 +321,130 @@ Pandoc (Meta {unMeta = fromList [("generator",MetaInlines [Str "pandoc"]),("titl
,[Plain [Str "3"]]]
,[[Plain [Str "4"]]
,[Plain [Str "5"]]
- ,[Plain [Str "6"]]]]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.3333333333333333,0.3333333333333333,0.3333333333333333]
+ [[Plain [Str "X"]]
+ ,[Plain [Str "Y"]]
+ ,[Plain [Str "Z"]]]
+ [[[Plain [Str "1"]]
+ ,[Para [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,Header 2 ("",[],[]) [Str "Tables",Space,Str "without",Space,Str "Headers"]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ []
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ []
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ []
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,HorizontalRule
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ []
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]
+ ,[Plain [Str "3"]]]
+ ,[[Plain [Str "4"]]
+ ,[Plain [Str "5"]]
+ ,[Plain [Str "6"]]]]
+,Header 2 ("",[],[]) [Str "Empty",Space,Str "Tables"]
+,Para [Str "This",Space,Str "section",Space,Str "should",Space,Str "be",Space,Str "empty."]]
diff --git a/tests/latex-reader.latex b/tests/latex-reader.latex
index 2ebdfed99..4324dbfbe 100644
--- a/tests/latex-reader.latex
+++ b/tests/latex-reader.latex
@@ -845,4 +845,31 @@ indented.
\$ \% \& \# \_ \{ \}
+\section{Block newcommands}
+
+See e.g. issues #1866, #1835
+
+\newcommand{\FIG}[3]{
+ \begin{figure}[h!]
+ \centering
+ \includegraphics[width=#2\columnwidth,angle=0]{#1}
+ \caption{#3}
+ \label{fig:#1}
+ \end{figure}
+}
+
+\newcommand{\separator}{\vspace{4em}}
+
+\separator
+
+\FIG{lalune.jpg}{0.5}{Test caption}
+
+\newcommand{\wbal}{The Wikibook about \LaTeX}
+
+\wbal is a good resource for learning \LaTeX.
+
+\separator with trailing inlines
+
+\FIG{lalune.jpg}{0.5}{Test caption} with trailing inlines
+
\end{document}
diff --git a/tests/latex-reader.native b/tests/latex-reader.native
index abc4b05a7..fbc191125 100644
--- a/tests/latex-reader.native
+++ b/tests/latex-reader.native
@@ -372,4 +372,13 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
[[Para [Str "And",Space,Str "in",Space,Str "list",Space,Str "items.",Note [Para [Str "In",Space,Str "list."]]]]]
,Para [Str "This",Space,Str "paragraph",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "part",Space,Str "of",Space,Str "the",Space,Str "note,",Space,Str "as",Space,Str "it",Space,Str "is",Space,Str "not",Space,Str "indented."]
,Header 1 ("escaped-characters",[],[]) [Str "Escaped",Space,Str "characters"]
-,Para [Str "$",Space,Str "%",Space,Str "&",Space,Str "#",Space,Str "_",Space,Str "{",Space,Str "}"]]
+,Para [Str "$",Space,Str "%",Space,Str "&",Space,Str "#",Space,Str "_",Space,Str "{",Space,Str "}"]
+,Header 1 ("block-newcommands",[],[]) [Str "Block",Space,Str "newcommands"]
+,Para [Str "See",Space,Str "e.g.",Space,Str "issues",Space,Str "#1866,",Space,Str "#1835"]
+,RawBlock (Format "latex") "\\vspace{4em}"
+,Para [RawInline (Format "latex") "\\centering",Image [Str "Test",Space,Str "caption",Span ("",[],[("data-label","fig:lalune.jpg")]) []] ("lalune.jpg","fig:")]
+,Para [Span ("",[],[]) [Str "The",Space,Str "Wikibook",Space,Str "about",Space,Str "LaTeX"],Str "is",Space,Str "a",Space,Str "good",Space,Str "resource",Space,Str "for",Space,Str "learning",Space,Str "LaTeX."]
+,RawBlock (Format "latex") "\\vspace{4em}"
+,Para [Str "with",Space,Str "trailing",Space,Str "inlines"]
+,Para [RawInline (Format "latex") "\\centering",Image [Str "Test",Space,Str "caption",Span ("",[],[("data-label","fig:lalune.jpg")]) []] ("lalune.jpg","fig:")]
+,Para [Str "with",Space,Str "trailing",Space,Str "inlines"]]
diff --git a/tests/lhs-test.html b/tests/lhs-test.html
index bde505a1e..5b5f9ccc2 100644
--- a/tests/lhs-test.html
+++ b/tests/lhs-test.html
@@ -7,31 +7,49 @@
<title></title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
+div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; }
-code > span.dt { color: #902000; }
-code > span.dv { color: #40a070; }
-code > span.bn { color: #40a070; }
-code > span.fl { color: #40a070; }
-code > span.ch { color: #4070a0; }
-code > span.st { color: #4070a0; }
-code > span.co { color: #60a0b0; font-style: italic; }
-code > span.ot { color: #007020; }
-code > span.al { color: #ff0000; font-weight: bold; }
-code > span.fu { color: #06287e; }
-code > span.er { color: #ff0000; font-weight: bold; }
+code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code > span.dt { color: #902000; } /* DataType */
+code > span.dv { color: #40a070; } /* DecVal */
+code > span.bn { color: #40a070; } /* BaseN */
+code > span.fl { color: #40a070; } /* Float */
+code > span.ch { color: #4070a0; } /* Char */
+code > span.st { color: #4070a0; } /* String */
+code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code > span.ot { color: #007020; } /* Other */
+code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code > span.fu { color: #06287e; } /* Function */
+code > span.er { color: #ff0000; font-weight: bold; } /* Error */
+code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+code > span.cn { color: #880000; } /* Constant */
+code > span.sc { color: #4070a0; } /* SpecialChar */
+code > span.vs { color: #4070a0; } /* VerbatimString */
+code > span.ss { color: #bb6688; } /* SpecialString */
+code > span.im { } /* Import */
+code > span.va { color: #19177c; } /* Variable */
+code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code > span.op { color: #666666; } /* Operator */
+code > span.bu { } /* BuiltIn */
+code > span.ex { } /* Extension */
+code > span.pp { color: #bc7a00; } /* Preprocessor */
+code > span.at { color: #7d9029; } /* Attribute */
+code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
</head>
<body>
<h1 id="lhs-test">lhs test</h1>
<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to return a single value:</p>
-<pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="ot">unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
+<div class="sourceCode"><pre class="sourceCode literate haskell"><code class="sourceCode haskell"><span class="ot">unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry
- <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre>
+ <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre></div>
<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the second item of the pair).</p>
<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
<p>Block quote:</p>
diff --git a/tests/lhs-test.html+lhs b/tests/lhs-test.html+lhs
index fcdcad303..0124b84d5 100644
--- a/tests/lhs-test.html+lhs
+++ b/tests/lhs-test.html+lhs
@@ -7,31 +7,49 @@
<title></title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
+div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; }
-code > span.dt { color: #902000; }
-code > span.dv { color: #40a070; }
-code > span.bn { color: #40a070; }
-code > span.fl { color: #40a070; }
-code > span.ch { color: #4070a0; }
-code > span.st { color: #4070a0; }
-code > span.co { color: #60a0b0; font-style: italic; }
-code > span.ot { color: #007020; }
-code > span.al { color: #ff0000; font-weight: bold; }
-code > span.fu { color: #06287e; }
-code > span.er { color: #ff0000; font-weight: bold; }
+code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
+code > span.dt { color: #902000; } /* DataType */
+code > span.dv { color: #40a070; } /* DecVal */
+code > span.bn { color: #40a070; } /* BaseN */
+code > span.fl { color: #40a070; } /* Float */
+code > span.ch { color: #4070a0; } /* Char */
+code > span.st { color: #4070a0; } /* String */
+code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
+code > span.ot { color: #007020; } /* Other */
+code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
+code > span.fu { color: #06287e; } /* Function */
+code > span.er { color: #ff0000; font-weight: bold; } /* Error */
+code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
+code > span.cn { color: #880000; } /* Constant */
+code > span.sc { color: #4070a0; } /* SpecialChar */
+code > span.vs { color: #4070a0; } /* VerbatimString */
+code > span.ss { color: #bb6688; } /* SpecialString */
+code > span.im { } /* Import */
+code > span.va { color: #19177c; } /* Variable */
+code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
+code > span.op { color: #666666; } /* Operator */
+code > span.bu { } /* BuiltIn */
+code > span.ex { } /* Extension */
+code > span.pp { color: #bc7a00; } /* Preprocessor */
+code > span.at { color: #7d9029; } /* Attribute */
+code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
+code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
+code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
+code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
</head>
<body>
<h1 id="lhs-test">lhs test</h1>
<p><code>unsplit</code> is an arrow that takes a pair of values and combines them to return a single value:</p>
-<pre class="sourceCode literate literatehaskell"><code class="sourceCode literatehaskell"><span class="ot">&gt; unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
+<div class="sourceCode"><pre class="sourceCode literate literatehaskell"><code class="sourceCode literatehaskell"><span class="ot">&gt; unsplit ::</span> (<span class="dt">Arrow</span> a) <span class="ot">=&gt;</span> (b <span class="ot">-&gt;</span> c <span class="ot">-&gt;</span> d) <span class="ot">-&gt;</span> a (b, c) d
<span class="ot">&gt;</span> unsplit <span class="fu">=</span> arr <span class="fu">.</span> uncurry
-<span class="ot">&gt;</span> <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre>
+<span class="ot">&gt;</span> <span class="co">-- arr (\op (x,y) -&gt; x `op` y)</span></code></pre></div>
<p><code>(***)</code> combines two arrows into a new arrow by running the two arrows on a pair of values (one arrow on the first item of the pair and one arrow on the second item of the pair).</p>
<pre><code>f *** g = first f &gt;&gt;&gt; second g</code></pre>
<p>Block quote:</p>
diff --git a/tests/lhs-test.latex b/tests/lhs-test.latex
index 6f2fdfb77..626a74cfa 100644
--- a/tests/lhs-test.latex
+++ b/tests/lhs-test.latex
@@ -23,6 +23,24 @@
\usepackage{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+\ifxetex
+ \usepackage[setpagesize=false, % page size defined by xetex
+ unicode=false, % unicode breaks when used with xetex
+ xetex]{hyperref}
+\else
+ \usepackage[unicode=true]{hyperref}
+\fi
+\usepackage[usenames,dvipsnames]{color}
+\hypersetup{breaklinks=true,
+ bookmarks=true,
+ pdfauthor={},
+ pdftitle={},
+ colorlinks=true,
+ citecolor=blue,
+ urlcolor=blue,
+ linkcolor=magenta,
+ pdfborder={0 0 0}}
+\urlstyle{same} % don't use monospace font for urls
\usepackage{color}
\usepackage{fancyvrb}
\newcommand{\VerbBar}{|}
@@ -35,39 +53,51 @@
\newcommand{\DecValTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
\newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
\newcommand{\FloatTok}[1]{\textcolor[rgb]{0.25,0.63,0.44}{{#1}}}
+\newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.53,0.00,0.00}{{#1}}}
\newcommand{\CharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
\newcommand{\StringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.25,0.44,0.63}{{#1}}}
+\newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.73,0.40,0.53}{{#1}}}
+\newcommand{\ImportTok}[1]{{#1}}
\newcommand{\CommentTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textit{{#1}}}}
+\newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.73,0.13,0.13}{\textit{{#1}}}}
+\newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
\newcommand{\OtherTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{{#1}}}
-\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
\newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.02,0.16,0.49}{{#1}}}
+\newcommand{\VariableTok}[1]{\textcolor[rgb]{0.10,0.09,0.49}{{#1}}}
+\newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.00,0.44,0.13}{\textbf{{#1}}}}
+\newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.40,0.40,0.40}{{#1}}}
+\newcommand{\BuiltInTok}[1]{{#1}}
+\newcommand{\ExtensionTok}[1]{{#1}}
+\newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.74,0.48,0.00}{{#1}}}
+\newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.49,0.56,0.16}{{#1}}}
\newcommand{\RegionMarkerTok}[1]{{#1}}
+\newcommand{\InformationTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\WarningTok}[1]{\textcolor[rgb]{0.38,0.63,0.69}{\textbf{\textit{{#1}}}}}
+\newcommand{\AlertTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
\newcommand{\ErrorTok}[1]{\textcolor[rgb]{1.00,0.00,0.00}{\textbf{{#1}}}}
\newcommand{\NormalTok}[1]{{#1}}
-\ifxetex
- \usepackage[setpagesize=false, % page size defined by xetex
- unicode=false, % unicode breaks when used with xetex
- xetex]{hyperref}
-\else
- \usepackage[unicode=true]{hyperref}
-\fi
-\hypersetup{breaklinks=true,
- bookmarks=true,
- pdfauthor={},
- pdftitle={},
- colorlinks=true,
- citecolor=blue,
- urlcolor=blue,
- linkcolor=magenta,
- pdfborder={0 0 0}}
-\urlstyle{same} % don't use monospace font for urls
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{0}
\date{}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
\begin{document}
\section{lhs test}\label{lhs-test}
diff --git a/tests/lhs-test.latex+lhs b/tests/lhs-test.latex+lhs
index 77f0e08ff..029789ba8 100644
--- a/tests/lhs-test.latex+lhs
+++ b/tests/lhs-test.latex+lhs
@@ -23,8 +23,6 @@
\usepackage{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
-\usepackage{listings}
-\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
\ifxetex
\usepackage[setpagesize=false, % page size defined by xetex
unicode=false, % unicode breaks when used with xetex
@@ -32,6 +30,7 @@
\else
\usepackage[unicode=true]{hyperref}
\fi
+\usepackage[usenames,dvipsnames]{color}
\hypersetup{breaklinks=true,
bookmarks=true,
pdfauthor={},
@@ -42,13 +41,27 @@
linkcolor=magenta,
pdfborder={0 0 0}}
\urlstyle{same} % don't use monospace font for urls
+\usepackage{listings}
+\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{0}
\date{}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
\begin{document}
\section{lhs test}\label{lhs-test}
diff --git a/tests/markdown-reader-more.native b/tests/markdown-reader-more.native
index 30da0afbb..b046d44d5 100644
--- a/tests/markdown-reader-more.native
+++ b/tests/markdown-reader-more.native
@@ -17,6 +17,7 @@
,Header 3 ("my-header",[],[]) [Str "my",Space,Str "header"]
,Header 2 ("in-math",[],[]) [Str "$",Space,Str "in",Space,Str "math"]
,Para [Math InlineMath "\\$2 + \\$3"]
+,Para [Math InlineMath "x = \\text{the $n$th root of $y$}"]
,Para [Str "This",Space,Str "should",Space,Str "not",Space,Str "be",Space,Str "math:"]
,Para [Str "$PATH",Space,Str "90",Space,Str "$PATH"]
,Header 2 ("commented-out-list-item",[],[]) [Str "Commented-out",Space,Str "list",Space,Str "item"]
@@ -75,9 +76,12 @@
,Header 3 ("my-other-header",[],[]) [Str "My",Space,Str "other",Space,Str "header"]
,Para [Str "A",Space,Str "link",Space,Str "to",Space,Link [Str "My",Space,Str "header"] ("#my-header-1",""),Str "."]
,Para [Str "Another",Space,Str "link",Space,Str "to",Space,Link [Str "it"] ("#my-header-1",""),Str "."]
+,Para [Str "Should",Space,Str "be",Space,Link [Str "case",Space,Str "insensitive"] ("#my-header-1",""),Str "."]
,Para [Str "Link",Space,Str "to",Space,Link [Str "Explicit",Space,Str "header",Space,Str "attributes"] ("#foobar",""),Str "."]
,Para [Str "But",Space,Str "this",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "link",Space,Str "to",Space,Link [Str "My",Space,Str "other",Space,Str "header"] ("/foo",""),Str ",",Space,Str "since",Space,Str "the",Space,Str "reference",Space,Str "is",Space,Str "defined."]
,Header 2 ("foobar",["baz"],[("key","val")]) [Str "Explicit",Space,Str "header",Space,Str "attributes"]
+,BlockQuote
+ [Header 2 ("foobar",["baz"],[("key","val")]) [Str "Header",Space,Str "attributes",Space,Str "inside",Space,Str "block",Space,Str "quote"]]
,Header 2 ("line-blocks",[],[]) [Str "Line",Space,Str "blocks"]
,Para [Str "But",Space,Str "can",Space,Str "a",Space,Str "bee",Space,Str "be",Space,Str "said",Space,Str "to",Space,Str "be",LineBreak,Str "\160\160\160\160or",Space,Str "not",Space,Str "to",Space,Str "be",Space,Str "an",Space,Str "entire",Space,Str "bee,",LineBreak,Str "\160\160\160\160\160\160\160\160when",Space,Str "half",Space,Str "the",Space,Str "bee",Space,Str "is",Space,Str "not",Space,Str "a",Space,Str "bee,",LineBreak,Str "\160\160\160\160\160\160\160\160\160\160\160\160due",Space,Str "to",Space,Str "some",Space,Str "ancient",Space,Str "injury?"]
,Para [Str "Continuation",Space,Str "line",LineBreak,Str "\160\160and",Space,Str "another"]
@@ -147,8 +151,15 @@
,Para [Link [Str "link"] ("/hi(there)","")]
,Para [Link [Str "link"] ("/hithere)","")]
,Para [Link [Str "linky"] ("hi_(there_(nested))","")]
+,Header 2 ("backslashes-in-link-references",[],[]) [Str "Backslashes",Space,Str "in",Space,Str "link",Space,Str "references"]
+,Para [Link [Str "*",RawInline (Format "tex") "\\a"] ("b","")]
,Header 2 ("reference-link-fallbacks",[],[]) [Str "Reference",Space,Str "link",Space,Str "fallbacks"]
,Para [Str "[",Emph [Str "not",Space,Str "a",Space,Str "link"],Str "]",Space,Str "[",Emph [Str "nope"],Str "]\8230"]
+,Header 2 ("reference-link-followed-by-a-citation",[],[]) [Str "Reference",Space,Str "link",Space,Str "followed",Space,Str "by",Space,Str "a",Space,Str "citation"]
+,Para [Str "MapReduce",Space,Str "is",Space,Str "a",Space,Str "paradigm",Space,Str "popularized",Space,Str "by",Space,Link [Str "Google"] ("http://google.com",""),Space,Cite [Citation {citationId = "mapreduce", citationPrefix = [], citationSuffix = [], citationMode = NormalCitation, citationNoteNum = 0, citationHash = 0}] [Str "[@mapreduce]"],Space,Str "as",Space,Str "its",Space,Str "most",Space,Str "vocal",Space,Str "proponent."]
,Header 2 ("empty-reference-links",[],[]) [Str "Empty",Space,Str "reference",Space,Str "links"]
,Para [Str "bar"]
-,Para [Link [Str "foo2"] ("","")]]
+,Para [Link [Str "foo2"] ("","")]
+,Header 2 ("wrapping-shouldnt-introduce-new-list-items",[],[]) [Str "Wrapping",Space,Str "shouldn\8217t",Space,Str "introduce",Space,Str "new",Space,Str "list",Space,Str "items"]
+,BulletList
+ [[Plain [Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "blah",Space,Str "2015."]]]]
diff --git a/tests/markdown-reader-more.txt b/tests/markdown-reader-more.txt
index c486f8885..4906a2eea 100644
--- a/tests/markdown-reader-more.txt
+++ b/tests/markdown-reader-more.txt
@@ -60,6 +60,8 @@
$\$2 + \$3$
+$x = \text{the $n$th root of $y$}$
+
This should not be math:
$PATH 90 $PATH
@@ -166,6 +168,8 @@ A link to [My header].
Another link to [it][My header].
+Should be [case insensitive][my header].
+
Link to [Explicit header attributes].
[my other header]: /foo
@@ -174,6 +178,8 @@ But this is not a link to [My other header], since the reference is defined.
## Explicit header attributes {#foobar .baz key="val"}
+> ## Header attributes inside block quote {#foobar .baz key="val"}
+
## Line blocks
| But can a bee be said to be
@@ -254,10 +260,21 @@ Empty cells
[linky]: hi_(there_(nested))
+## Backslashes in link references
+
+[\*\a](b)
+
## Reference link fallbacks
[*not a link*] [*nope*]...
+## Reference link followed by a citation
+
+MapReduce is a paradigm popularized by [Google] [@mapreduce] as its
+most vocal proponent.
+
+[Google]: http://google.com
+
## Empty reference links
[foo2]:
@@ -265,3 +282,8 @@ Empty cells
bar
[foo2]
+
+## Wrapping shouldn't introduce new list items
+
+- blah blah blah blah blah blah blah blah blah blah blah blah blah blah 2015.
+
diff --git a/tests/media/rId25.jpg b/tests/media/rId25.jpg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/media/rId25.jpg
diff --git a/tests/media/rId26.jpg b/tests/media/rId26.jpg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/media/rId26.jpg
diff --git a/tests/media/rId27.jpg b/tests/media/rId27.jpg
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/media/rId27.jpg
diff --git a/tests/mediawiki-reader.native b/tests/mediawiki-reader.native
index 2e97e9484..2f508c32f 100644
--- a/tests/mediawiki-reader.native
+++ b/tests/mediawiki-reader.native
@@ -72,7 +72,7 @@ Pandoc (Meta {unMeta = fromList []})
,Para [Str "Nother",Space,Str "paragraph."]
,Header 2 ("external-links",[],[]) [Str "external",Space,Str "links"]
,Para [Link [Emph [Str "Google"],Space,Str "search",Space,Str "engine"] ("http://google.com","")]
-,Para [Link [Str "http://johnmacfarlane.net/pandoc/"] ("http://johnmacfarlane.net/pandoc/","")]
+,Para [Link [Str "http://pandoc.org"] ("http://pandoc.org","")]
,Para [Link [Str "1"] ("http://google.com",""),Space,Link [Str "2"] ("http://yahoo.com","")]
,Para [Link [Str "email",Space,Str "me"] ("mailto:info@example.org","")]
,Header 2 ("internal-links",[],[]) [Str "internal",Space,Str "links"]
diff --git a/tests/mediawiki-reader.wiki b/tests/mediawiki-reader.wiki
index 6a6bc226d..f30dafa33 100644
--- a/tests/mediawiki-reader.wiki
+++ b/tests/mediawiki-reader.wiki
@@ -141,7 +141,7 @@ Nother paragraph.
[http://google.com ''Google'' search engine]
-http://johnmacfarlane.net/pandoc/
+http://pandoc.org
[http://google.com] [http://yahoo.com]
diff --git a/tests/odt/markdown/bold.md b/tests/odt/markdown/bold.md
new file mode 100644
index 000000000..fa4eb0431
--- /dev/null
+++ b/tests/odt/markdown/bold.md
@@ -0,0 +1 @@
+Here comes **bold** text \ No newline at end of file
diff --git a/tests/odt/markdown/citation.md b/tests/odt/markdown/citation.md
new file mode 100644
index 000000000..adcc9f0ff
--- /dev/null
+++ b/tests/odt/markdown/citation.md
@@ -0,0 +1 @@
+Some text[@Ex] with a citation. \ No newline at end of file
diff --git a/tests/odt/markdown/endnote.md b/tests/odt/markdown/endnote.md
new file mode 100644
index 000000000..679af3fdc
--- /dev/null
+++ b/tests/odt/markdown/endnote.md
@@ -0,0 +1,3 @@
+Some text[^1] with an endnote.
+
+[^1]: Endnote text \ No newline at end of file
diff --git a/tests/odt/markdown/externalLink.md b/tests/odt/markdown/externalLink.md
new file mode 100644
index 000000000..14f48d0f5
--- /dev/null
+++ b/tests/odt/markdown/externalLink.md
@@ -0,0 +1 @@
+Here comes an [external link](http://example.com/) to example.com. \ No newline at end of file
diff --git a/tests/odt/markdown/footnote.md b/tests/odt/markdown/footnote.md
new file mode 100644
index 000000000..973ae2d3a
--- /dev/null
+++ b/tests/odt/markdown/footnote.md
@@ -0,0 +1,3 @@
+Some text[^1] with a footnote.
+
+[^1]: Footnote text \ No newline at end of file
diff --git a/tests/odt/markdown/headers.md b/tests/odt/markdown/headers.md
new file mode 100644
index 000000000..ea5d4452c
--- /dev/null
+++ b/tests/odt/markdown/headers.md
@@ -0,0 +1,9 @@
+# A header (Lv 1)
+
+A paragraph
+
+## Another header (Lv 2)
+
+Another paragraph
+
+# Back to Level 1 \ No newline at end of file
diff --git a/tests/odt/markdown/horizontalRule.md b/tests/odt/markdown/horizontalRule.md
new file mode 100644
index 000000000..73b314ff7
--- /dev/null
+++ b/tests/odt/markdown/horizontalRule.md
@@ -0,0 +1 @@
+--- \ No newline at end of file
diff --git a/tests/odt/markdown/image.md b/tests/odt/markdown/image.md
new file mode 100644
index 000000000..3862d709e
--- /dev/null
+++ b/tests/odt/markdown/image.md
@@ -0,0 +1 @@
+![](10000000000000FA000000FAD6A15225.jpg) \ No newline at end of file
diff --git a/tests/odt/markdown/imageIndex.md b/tests/odt/markdown/imageIndex.md
new file mode 100644
index 000000000..6719ab8a8
--- /dev/null
+++ b/tests/odt/markdown/imageIndex.md
@@ -0,0 +1,6 @@
+# Abbildungsverzeichnis
+
+Abbildung 1: Image caption
+
+![Abbildung 1: Image caption](10000000000000FA000000FAD6A15225.jpg)
+
diff --git a/tests/odt/markdown/imageWithCaption.md b/tests/odt/markdown/imageWithCaption.md
new file mode 100644
index 000000000..0046ae141
--- /dev/null
+++ b/tests/odt/markdown/imageWithCaption.md
@@ -0,0 +1 @@
+![Abbildung 1: Image caption](10000000000000FA000000FAD6A15225.jpg) \ No newline at end of file
diff --git a/tests/odt/markdown/italic.md b/tests/odt/markdown/italic.md
new file mode 100644
index 000000000..b4d2f3d40
--- /dev/null
+++ b/tests/odt/markdown/italic.md
@@ -0,0 +1 @@
+Here comes *italic* text \ No newline at end of file
diff --git a/tests/odt/markdown/listBlocks.md b/tests/odt/markdown/listBlocks.md
new file mode 100644
index 000000000..22c77bb2b
--- /dev/null
+++ b/tests/odt/markdown/listBlocks.md
@@ -0,0 +1,6 @@
+<text:list xml:id="list2666723676250588421" text:style-name="L6">
+<text:list-header>
+<text:p text:style-name="P1">Indented text in a list.</text:p>
+</text:list-header>
+<text:list-item>
+<text:p text:style-name="P1">This is a numbered block.<text:line-break/>It contains several paragraphs of text.<text:line-break/>Like this.</text:p></text:list-item><text:list-item><text:p text:style-name="P1">Next item.</text:p></text:list-item></text:list></office:text></office:body></office:document-content> \ No newline at end of file
diff --git a/tests/odt/markdown/paragraph.md b/tests/odt/markdown/paragraph.md
new file mode 100644
index 000000000..0a822e322
--- /dev/null
+++ b/tests/odt/markdown/paragraph.md
@@ -0,0 +1,5 @@
+This is a paragraph.
+
+This is another paragraph.
+
+This is a third one. \ No newline at end of file
diff --git a/tests/odt/markdown/strikeout.md b/tests/odt/markdown/strikeout.md
new file mode 100644
index 000000000..6ae4571dd
--- /dev/null
+++ b/tests/odt/markdown/strikeout.md
@@ -0,0 +1 @@
+Here comes text that was ~~striken out~~. \ No newline at end of file
diff --git a/tests/odt/markdown/trackedChanges.md b/tests/odt/markdown/trackedChanges.md
new file mode 100644
index 000000000..f0bd478a3
--- /dev/null
+++ b/tests/odt/markdown/trackedChanges.md
@@ -0,0 +1 @@
+Some text with and inserted text. \ No newline at end of file
diff --git a/tests/odt/markdown/underlined.md b/tests/odt/markdown/underlined.md
new file mode 100644
index 000000000..05fb92379
--- /dev/null
+++ b/tests/odt/markdown/underlined.md
@@ -0,0 +1 @@
+Here comes *underlined* text \ No newline at end of file
diff --git a/tests/odt/native/blockquote.native b/tests/odt/native/blockquote.native
new file mode 100644
index 000000000..8c9409dde
--- /dev/null
+++ b/tests/odt/native/blockquote.native
@@ -0,0 +1 @@
+[Para [Str "Normal"],BlockQuote [Para [Str "Indented",Space,Str "(1cm)"]]] \ No newline at end of file
diff --git a/tests/odt/native/orderedListMixed.native b/tests/odt/native/orderedListMixed.native
new file mode 100644
index 000000000..a50f5e2ad
--- /dev/null
+++ b/tests/odt/native/orderedListMixed.native
@@ -0,0 +1 @@
+Pandoc (Meta {unMeta = fromList []}) [OrderedList (1,Decimal,Period) [[Plain [Str "A",Space,Str "list",Space,Str "item"]],[Plain [Str "A",Space,Str "second"]],[Para [Str "A",Space,Str "third"],OrderedList (1,Decimal,Period) [[Para [Str "New",Space,Str "level!"],OrderedList (1,LowerAlpha,OneParen) [[Plain [Str "And",Space,Str "another!"]],[Plain [Str "It's",Space,Str "great",Space,Str "up",Space,Str "here!"]]]],[Plain [Str "Oh",Space,Str "noes"]],[Plain [Str "We",Space,Str "fell!"]]]],[Plain [Str "Maybe",Space,Str "someone"]],[Plain [Str "Pushed",Space,Str "us?"]]]] \ No newline at end of file
diff --git a/tests/odt/native/orderedListRoman.native b/tests/odt/native/orderedListRoman.native
new file mode 100644
index 000000000..f186e0735
--- /dev/null
+++ b/tests/odt/native/orderedListRoman.native
@@ -0,0 +1 @@
+Pandoc (Meta {unMeta = fromList []}) [OrderedList (1,UpperRoman,Period) [[Plain[Str "A",Space,Str "list",Space,Str "item"]],[Plain [Str "A",Space,Str "second"]],[Para [Str "A",Space,Str "third"],OrderedList (1,UpperRoman,Period) [[Para [Str "New",Space,Str "level!"],OrderedList (1,UpperRoman,Period) [[Plain [Str "And",Space,Str "another!"]],[Plain [Str "It's",Space,Str "great",Space,Str "up",Space,Str "here!"]]]],[Plain [Str "Oh",Space,Str "noes"]],[Plain [Str "We",Space,Str "fell!"]]]],[Plain [Str "Maybe",Space,Str "someone"]],[Plain [Str "Pushed",Space,Str "us?"]]]] \ No newline at end of file
diff --git a/tests/odt/native/orderedListSimple.native b/tests/odt/native/orderedListSimple.native
new file mode 100644
index 000000000..90a51856a
--- /dev/null
+++ b/tests/odt/native/orderedListSimple.native
@@ -0,0 +1 @@
+Pandoc (Meta {unMeta = fromList []}) [OrderedList (1,Decimal,Period) [[Plain [Str "A",Space,Str "list",Space,Str "item"]],[Plain [Str "A",Space,Str "second"]],[Para [Str "A",Space,Str "third"],OrderedList (1,Decimal,Period) [[Para [Str "New",Space,Str "level!"],OrderedList (1,Decimal,Period) [[Plain [Str "And",Space,Str "another!"]],[Plain [Str "It's",Space,Str "great",Space,Str "up",Space,Str "here!"]]]],[Plain [Str "Oh",Space,Str "noes"]],[Plain [Str "We",Space,Str "fell!"]]]],[Plain [Str "Maybe",Space,Str "someone"]],[Plain [Str "Pushed",Space,Str "us?"]]]] \ No newline at end of file
diff --git a/tests/odt/native/referenceToChapter.native b/tests/odt/native/referenceToChapter.native
new file mode 100644
index 000000000..fc6c6cf5c
--- /dev/null
+++ b/tests/odt/native/referenceToChapter.native
@@ -0,0 +1 @@
+[Header 1 ("a-chapter",[],[]) [Span ("anchor",[],[]) [],Str "A",Space,Str "chapter"],Para [Str "Some",Space,Str "text."],Header 1 ("another-chapter",[],[]) [Str "Another",Space,Str "chapter"],Para [Str "A",Space,Str "reference",Space,Str "to",Space,Str "."],Para [Str "A",Space,Str "reference",Space,Str "to",Space,Link [Str "A",Space,Str "chapter"] ("#anchor",""),Str "."]] \ No newline at end of file
diff --git a/tests/odt/native/referenceToListItem.native b/tests/odt/native/referenceToListItem.native
new file mode 100644
index 000000000..d009f8d23
--- /dev/null
+++ b/tests/odt/native/referenceToListItem.native
@@ -0,0 +1 @@
+[OrderedList (1,Decimal,Period) [[Plain [Span ("anchor",[],[]) [],Str "A",Space,Str "list",Space,Str "item"]],[Plain [Str "Another",Space,Str "list",Space,Str "item"]]],Para [Str "A",Space,Str "reference",Space,Str "to",Space,Str "list",Space,Str "item",Space,Link [Str "1."] ("#anchor",""),Str "."],Para [],Para []] \ No newline at end of file
diff --git a/tests/odt/native/referenceToText.native b/tests/odt/native/referenceToText.native
new file mode 100644
index 000000000..45f7ac44c
--- /dev/null
+++ b/tests/odt/native/referenceToText.native
@@ -0,0 +1 @@
+[Para [Span ("an anchor",[],[]) [],Str "Some",Space,Str "text."],Para [Str "A",Space,Str "reference",Space,Str "to",Space,Link [Str "Some",Space,Str "text"] ("#an anchor",""),Str "."]] \ No newline at end of file
diff --git a/tests/odt/native/simpleTable.native b/tests/odt/native/simpleTable.native
new file mode 100644
index 000000000..f94026bd5
--- /dev/null
+++ b/tests/odt/native/simpleTable.native
@@ -0,0 +1 @@
+[Table [] [] [] [] [[[Plain [Str "Content"]],[Plain [Str "More",Space,Str "content"]]]],Para []] \ No newline at end of file
diff --git a/tests/odt/native/unicode.native b/tests/odt/native/unicode.native
new file mode 100644
index 000000000..b6ac9760c
--- /dev/null
+++ b/tests/odt/native/unicode.native
@@ -0,0 +1 @@
+[Para [Str "\8220\8221\8217\231\1256\169\188\1074\1073\1060\1064\246\201\181"]] \ No newline at end of file
diff --git a/tests/odt/native/unorderedList.native b/tests/odt/native/unorderedList.native
new file mode 100644
index 000000000..a8c083d13
--- /dev/null
+++ b/tests/odt/native/unorderedList.native
@@ -0,0 +1 @@
+[BulletList [[Plain [Str "A",Space,Str "list",Space,Str "item"]],[Plain [Str "A",Space,Str "second"]],[Para [Str "A",Space,Str "third"],BulletList [[Para [Str "New",Space,Str "level!"],BulletList [[Plain [Str "And",Space,Str "another!"]],[Plain [Str "It's",Space,Str "great",Space,Str "up",Space,Str "here!"]]]],[Plain [Str "Oh",Space,Str "noes"]],[Plain [Str "We",Space,Str "fell!"]]]],[Plain [Str "Maybe",Space,Str "someone"]],[Plain [Str "Pushed",Space,Str "us?"]]]] \ No newline at end of file
diff --git a/tests/odt/odt/blockquote.odt b/tests/odt/odt/blockquote.odt
new file mode 100644
index 000000000..0114e308f
--- /dev/null
+++ b/tests/odt/odt/blockquote.odt
Binary files differ
diff --git a/tests/odt/odt/bold.odt b/tests/odt/odt/bold.odt
new file mode 100644
index 000000000..49285722e
--- /dev/null
+++ b/tests/odt/odt/bold.odt
Binary files differ
diff --git a/tests/odt/odt/citation.odt b/tests/odt/odt/citation.odt
new file mode 100644
index 000000000..b6dbe649e
--- /dev/null
+++ b/tests/odt/odt/citation.odt
Binary files differ
diff --git a/tests/odt/odt/endnote.odt b/tests/odt/odt/endnote.odt
new file mode 100644
index 000000000..c1aba45da
--- /dev/null
+++ b/tests/odt/odt/endnote.odt
Binary files differ
diff --git a/tests/odt/odt/expression.odt b/tests/odt/odt/expression.odt
new file mode 100644
index 000000000..1085d7008
--- /dev/null
+++ b/tests/odt/odt/expression.odt
Binary files differ
diff --git a/tests/odt/odt/expressionUnevaluated.odt b/tests/odt/odt/expressionUnevaluated.odt
new file mode 100644
index 000000000..64df660b6
--- /dev/null
+++ b/tests/odt/odt/expressionUnevaluated.odt
Binary files differ
diff --git a/tests/odt/odt/externalLink.odt b/tests/odt/odt/externalLink.odt
new file mode 100644
index 000000000..1d8f55489
--- /dev/null
+++ b/tests/odt/odt/externalLink.odt
Binary files differ
diff --git a/tests/odt/odt/footnote.odt b/tests/odt/odt/footnote.odt
new file mode 100644
index 000000000..74915c33c
--- /dev/null
+++ b/tests/odt/odt/footnote.odt
Binary files differ
diff --git a/tests/odt/odt/formula.odt b/tests/odt/odt/formula.odt
new file mode 100644
index 000000000..5cf5f3451
--- /dev/null
+++ b/tests/odt/odt/formula.odt
Binary files differ
diff --git a/tests/odt/odt/headers.odt b/tests/odt/odt/headers.odt
new file mode 100644
index 000000000..9212e9fb1
--- /dev/null
+++ b/tests/odt/odt/headers.odt
Binary files differ
diff --git a/tests/odt/odt/hiddenTextByStyle.odt b/tests/odt/odt/hiddenTextByStyle.odt
new file mode 100644
index 000000000..79c40ca98
--- /dev/null
+++ b/tests/odt/odt/hiddenTextByStyle.odt
Binary files differ
diff --git a/tests/odt/odt/hiddenTextByVariable.odt b/tests/odt/odt/hiddenTextByVariable.odt
new file mode 100644
index 000000000..ec793d466
--- /dev/null
+++ b/tests/odt/odt/hiddenTextByVariable.odt
Binary files differ
diff --git a/tests/odt/odt/horizontalRule.odt b/tests/odt/odt/horizontalRule.odt
new file mode 100644
index 000000000..df09386bc
--- /dev/null
+++ b/tests/odt/odt/horizontalRule.odt
Binary files differ
diff --git a/tests/odt/odt/image.odt b/tests/odt/odt/image.odt
new file mode 100644
index 000000000..c2fd1e407
--- /dev/null
+++ b/tests/odt/odt/image.odt
Binary files differ
diff --git a/tests/odt/odt/imageIndex.odt b/tests/odt/odt/imageIndex.odt
new file mode 100644
index 000000000..220a49047
--- /dev/null
+++ b/tests/odt/odt/imageIndex.odt
Binary files differ
diff --git a/tests/odt/odt/imageWithCaption.odt b/tests/odt/odt/imageWithCaption.odt
new file mode 100644
index 000000000..99b5b7af1
--- /dev/null
+++ b/tests/odt/odt/imageWithCaption.odt
Binary files differ
diff --git a/tests/odt/odt/italic.odt b/tests/odt/odt/italic.odt
new file mode 100644
index 000000000..d05cfeade
--- /dev/null
+++ b/tests/odt/odt/italic.odt
Binary files differ
diff --git a/tests/odt/odt/listBlocks.odt b/tests/odt/odt/listBlocks.odt
new file mode 100644
index 000000000..5855e9920
--- /dev/null
+++ b/tests/odt/odt/listBlocks.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListMixed.odt b/tests/odt/odt/orderedListMixed.odt
new file mode 100644
index 000000000..1aa50ff06
--- /dev/null
+++ b/tests/odt/odt/orderedListMixed.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListRoman.odt b/tests/odt/odt/orderedListRoman.odt
new file mode 100644
index 000000000..7266e89bc
--- /dev/null
+++ b/tests/odt/odt/orderedListRoman.odt
Binary files differ
diff --git a/tests/odt/odt/orderedListSimple.odt b/tests/odt/odt/orderedListSimple.odt
new file mode 100644
index 000000000..4fe543794
--- /dev/null
+++ b/tests/odt/odt/orderedListSimple.odt
Binary files differ
diff --git a/tests/odt/odt/paragraph.odt b/tests/odt/odt/paragraph.odt
new file mode 100644
index 000000000..b635b2164
--- /dev/null
+++ b/tests/odt/odt/paragraph.odt
Binary files differ
diff --git a/tests/odt/odt/referenceAllInOne.odt b/tests/odt/odt/referenceAllInOne.odt
new file mode 100644
index 000000000..e9f38e359
--- /dev/null
+++ b/tests/odt/odt/referenceAllInOne.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToChapter.odt b/tests/odt/odt/referenceToChapter.odt
new file mode 100644
index 000000000..d4be67b0b
--- /dev/null
+++ b/tests/odt/odt/referenceToChapter.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToListItem.odt b/tests/odt/odt/referenceToListItem.odt
new file mode 100644
index 000000000..be3aed245
--- /dev/null
+++ b/tests/odt/odt/referenceToListItem.odt
Binary files differ
diff --git a/tests/odt/odt/referenceToText.odt b/tests/odt/odt/referenceToText.odt
new file mode 100644
index 000000000..281055aa0
--- /dev/null
+++ b/tests/odt/odt/referenceToText.odt
Binary files differ
diff --git a/tests/odt/odt/simpleTable.odt b/tests/odt/odt/simpleTable.odt
new file mode 100644
index 000000000..a00622918
--- /dev/null
+++ b/tests/odt/odt/simpleTable.odt
Binary files differ
diff --git a/tests/odt/odt/strikeout.odt b/tests/odt/odt/strikeout.odt
new file mode 100644
index 000000000..3a3f1543a
--- /dev/null
+++ b/tests/odt/odt/strikeout.odt
Binary files differ
diff --git a/tests/odt/odt/table.odt b/tests/odt/odt/table.odt
new file mode 100644
index 000000000..7a2b1cfae
--- /dev/null
+++ b/tests/odt/odt/table.odt
Binary files differ
diff --git a/tests/odt/odt/tableWithCaption.odt b/tests/odt/odt/tableWithCaption.odt
new file mode 100644
index 000000000..d44654460
--- /dev/null
+++ b/tests/odt/odt/tableWithCaption.odt
Binary files differ
diff --git a/tests/odt/odt/trackedChanges.odt b/tests/odt/odt/trackedChanges.odt
new file mode 100644
index 000000000..5ac493ed7
--- /dev/null
+++ b/tests/odt/odt/trackedChanges.odt
Binary files differ
diff --git a/tests/odt/odt/underlined.odt b/tests/odt/odt/underlined.odt
new file mode 100644
index 000000000..d645717b8
--- /dev/null
+++ b/tests/odt/odt/underlined.odt
Binary files differ
diff --git a/tests/odt/odt/unicode.odt b/tests/odt/odt/unicode.odt
new file mode 100644
index 000000000..07e200425
--- /dev/null
+++ b/tests/odt/odt/unicode.odt
Binary files differ
diff --git a/tests/odt/odt/unorderedList.odt b/tests/odt/odt/unorderedList.odt
new file mode 100644
index 000000000..50a950024
--- /dev/null
+++ b/tests/odt/odt/unorderedList.odt
Binary files differ
diff --git a/tests/odt/odt/variable.odt b/tests/odt/odt/variable.odt
new file mode 100644
index 000000000..73ff5f648
--- /dev/null
+++ b/tests/odt/odt/variable.odt
Binary files differ
diff --git a/tests/pipe-tables.txt b/tests/pipe-tables.txt
index ee8d54d9f..83debd595 100644
--- a/tests/pipe-tables.txt
+++ b/tests/pipe-tables.txt
@@ -1,7 +1,7 @@
Simplest table without caption:
| Default1 | Default2 | Default3 |
-|----------|----------|----------|
+ |----------|----------|----------|
|12|12|12|
|123|123|123|
|1|1|1|
@@ -27,6 +27,7 @@ Simple table without caption:
Headerless table without caption:
+| | | |
|------:|:-----|:------:|
|12|12|12|
|123|123|123|
@@ -48,5 +49,6 @@ One-column:
Header-less one-column:
+| |
|:-:|
|hi|
diff --git a/tests/rst-reader.native b/tests/rst-reader.native
index c77d15775..1f402f835 100644
--- a/tests/rst-reader.native
+++ b/tests/rst-reader.native
@@ -322,12 +322,12 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Null
,Para [Str "And",Space,Str "now",Space,Str "with",Space,RawInline (Format "html") "<b>inline</b> <span id=\"test\">HTML</span>",Str "."]
,Null
-,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["sourceCode","haskell"],[]) "fmap id [1,2..10]",Str "."]
+,Para [Str "And",Space,Str "some",Space,Str "inline",Space,Str "haskell",Space,Code ("",["haskell","sourceCode"],[]) "fmap id [1,2..10]",Str "."]
,Null
,Null
-,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["sourceCode","python"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."]
+,Para [Str "Indirect",Space,Str "python",Space,Str "role",Space,Code ("",["python","indirect","sourceCode"],[]) "[x*x for x in [1,2,3,4,5]]",Str "."]
,Null
,Null
-,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["sourceCode","c"],[]) "int x = 15;",Str "."]
+,Para [Str "Different",Space,Str "indirect",Space,Str "C",Space,Code ("",["c","different-indirect","sourceCode"],[]) "int x = 15;",Str "."]
,Header 2 ("literal-symbols",[],[]) [Str "Literal",Space,Str "symbols"]
,Para [Str "2*2",Space,Str "=",Space,Str "4*1"]]
diff --git a/tests/s5-basic.html b/tests/s5-basic.html
index ceb896b8e..ac153d0f1 100644
--- a/tests/s5-basic.html
+++ b/tests/s5-basic.html
@@ -46,7 +46,7 @@
<div id="math" class="slide section level1">
<h1>Math</h1>
<ul>
-<li><span class="math">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
</ul>
</div>
</div>
diff --git a/tests/s5-fragment.html b/tests/s5-fragment.html
index e8a888972..81c578d25 100644
--- a/tests/s5-fragment.html
+++ b/tests/s5-fragment.html
@@ -5,5 +5,5 @@
</ul>
<h1 id="math">Math</h1>
<ul>
-<li><span class="math">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
</ul>
diff --git a/tests/s5-inserts.html b/tests/s5-inserts.html
index 455225f9b..2feed4173 100644
--- a/tests/s5-inserts.html
+++ b/tests/s5-inserts.html
@@ -27,7 +27,7 @@ STUFF INSERTED
</ul>
<h1 id="math">Math</h1>
<ul>
-<li><span class="math">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
+<li><span class="math inline">$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$</span></li>
</ul>
STUFF INSERTED
</body>
diff --git a/tests/tables.asciidoc b/tests/tables.asciidoc
index ba647866a..2a24544a3 100644
--- a/tests/tables.asciidoc
+++ b/tests/tables.asciidoc
@@ -65,4 +65,3 @@ Multiline table without column headers:
|First |row |12.0 |Example of a row that spans multiple lines.
|Second |row |5.0 |Here's another one. Note the blank line between rows.
|=======================================================================
-
diff --git a/tests/tables.haddock b/tests/tables.haddock
index 413ec97ad..f9efdc0de 100644
--- a/tests/tables.haddock
+++ b/tests/tables.haddock
@@ -74,4 +74,3 @@ Multiline table without column headers:
> the blank line between
> rows.
> ----------- ---------- ------------ --------------------------
-
diff --git a/tests/tables.opendocument b/tests/tables.opendocument
index ff304ef26..aa35abc91 100644
--- a/tests/tables.opendocument
+++ b/tests/tables.opendocument
@@ -63,7 +63,7 @@
</table:table-cell>
</table:table-row>
</table:table>
-<text:p text:style-name="Caption">Demonstration of simple table
+<text:p text:style-name="TableCaption">Demonstration of simple table
syntax.</text:p>
<text:p text:style-name="First_20_paragraph">Simple table without
caption:</text:p>
@@ -197,7 +197,7 @@ spaces:</text:p>
</table:table-cell>
</table:table-row>
</table:table>
-<text:p text:style-name="Caption">Demonstration of simple table
+<text:p text:style-name="TableCaption">Demonstration of simple table
syntax.</text:p>
<text:p text:style-name="First_20_paragraph">Multiline table with
caption:</text:p>
@@ -253,8 +253,8 @@ caption:</text:p>
</table:table-cell>
</table:table-row>
</table:table>
-<text:p text:style-name="Caption">Here's the caption. It may span multiple
-lines.</text:p>
+<text:p text:style-name="TableCaption">Here's the caption. It may span
+multiple lines.</text:p>
<text:p text:style-name="First_20_paragraph">Multiline table without
caption:</text:p>
<table:table table:name="Table5" table:style-name="Table5">
diff --git a/tests/tables.org b/tests/tables.org
index 8d9100d07..9eaf5e706 100644
--- a/tests/tables.org
+++ b/tests/tables.org
@@ -49,4 +49,3 @@ Multiline table without column headers:
| First | row | 12.0 | Example of a row that spans multiple lines. |
| Second | row | 5.0 | Here's another one. Note the blank line between rows. |
-
diff --git a/tests/tables.rst b/tests/tables.rst
index e77f69d97..25d5932ea 100644
--- a/tests/tables.rst
+++ b/tests/tables.rst
@@ -88,4 +88,3 @@ Multiline table without column headers:
| | | | the blank line between |
| | | | rows. |
+-------------+------------+--------------+----------------------------+
-
diff --git a/tests/test-pandoc.hs b/tests/test-pandoc.hs
index b7b1c30b1..f7c2f0c1f 100644
--- a/tests/test-pandoc.hs
+++ b/tests/test-pandoc.hs
@@ -8,8 +8,10 @@ import qualified Tests.Old
import qualified Tests.Readers.LaTeX
import qualified Tests.Readers.Markdown
import qualified Tests.Readers.Org
+import qualified Tests.Readers.HTML
import qualified Tests.Readers.RST
import qualified Tests.Readers.Docx
+import qualified Tests.Readers.Odt
import qualified Tests.Readers.Txt2Tags
import qualified Tests.Readers.EPUB
import qualified Tests.Writers.ConTeXt
@@ -20,6 +22,8 @@ import qualified Tests.Writers.Native
import qualified Tests.Writers.Markdown
import qualified Tests.Writers.Plain
import qualified Tests.Writers.AsciiDoc
+import qualified Tests.Writers.Docx
+import qualified Tests.Writers.RST
import qualified Tests.Shared
import qualified Tests.Walk
import Text.Pandoc.Shared (inDirectory)
@@ -38,13 +42,17 @@ tests = [ testGroup "Old" Tests.Old.tests
, testGroup "Markdown" Tests.Writers.Markdown.tests
, testGroup "Plain" Tests.Writers.Plain.tests
, testGroup "AsciiDoc" Tests.Writers.AsciiDoc.tests
+ , testGroup "Docx" Tests.Writers.Docx.tests
+ , testGroup "RST" Tests.Writers.RST.tests
]
, testGroup "Readers"
[ testGroup "LaTeX" Tests.Readers.LaTeX.tests
, testGroup "Markdown" Tests.Readers.Markdown.tests
+ , testGroup "HTML" Tests.Readers.HTML.tests
, testGroup "Org" Tests.Readers.Org.tests
, testGroup "RST" Tests.Readers.RST.tests
, testGroup "Docx" Tests.Readers.Docx.tests
+ , testGroup "Odt" Tests.Readers.Odt.tests
, testGroup "Txt2Tags" Tests.Readers.Txt2Tags.tests
, testGroup "EPUB" Tests.Readers.EPUB.tests
]
diff --git a/tests/twiki-reader.native b/tests/twiki-reader.native
new file mode 100644
index 000000000..6e199a1a9
--- /dev/null
+++ b/tests/twiki-reader.native
@@ -0,0 +1,174 @@
+Pandoc (Meta {unMeta = fromList []})
+[Header 1 ("header",[],[]) [Str "header"]
+,Header 2 ("header-level-two",[],[]) [Str "header",Space,Str "level",Space,Str "two"]
+,Header 3 ("header-level-3",[],[]) [Str "header",Space,Str "level",Space,Str "3"]
+,Header 4 ("header-level-four",[],[]) [Str "header",Space,Emph [Str "level"],Space,Str "four"]
+,Header 5 ("header-level-5",[],[]) [Str "header",Space,Str "level",Space,Str "5"]
+,Header 6 ("header-level-6",[],[]) [Str "header",Space,Str "level",Space,Str "6"]
+,Para [Str "---+++++++",Space,Str "not",Space,Str "a",Space,Str "header"]
+,Para [Str "--++",Space,Str "not",Space,Str "a",Space,Str "header"]
+,Header 1 ("emph-and-strong",[],[]) [Str "emph",Space,Str "and",Space,Str "strong"]
+,Para [Emph [Str "emph"],Space,Strong [Str "strong"]]
+,Para [Emph [Strong [Str "strong",Space,Str "and",Space,Str "emph"]]]
+,Para [Strong [Emph [Str "emph",Space,Str "inside"],Space,Str "strong"]]
+,Para [Strong [Str "strong",Space,Str "with",Space,Emph [Str "emph"]]]
+,Para [Emph [Strong [Str "strong",Space,Str "inside"],Space,Str "emph"]]
+,Header 1 ("horizontal-rule",[],[]) [Str "horizontal",Space,Str "rule"]
+,Para [Str "top"]
+,HorizontalRule
+,Para [Str "bottom"]
+,HorizontalRule
+,Header 1 ("nop",[],[]) [Str "nop"]
+,Para [Str "_not",Space,Str "emph_"]
+,Header 1 ("entities",[],[]) [Str "entities"]
+,Para [Str "hi",Space,Str "&",Space,Str "low"]
+,Para [Str "hi",Space,Str "&",Space,Str "low"]
+,Para [Str "G\246del"]
+,Para [Str "\777\2730"]
+,Header 1 ("comments",[],[]) [Str "comments"]
+,Para [Str "inline",Space,Str "comment"]
+,Para [Str "between",Space,Str "blocks"]
+,Header 1 ("linebreaks",[],[]) [Str "linebreaks"]
+,Para [Str "hi",LineBreak,Str "there"]
+,Para [Str "hi",LineBreak,Space,Str "there"]
+,Header 1 ("inline-code",[],[]) [Str "inline",Space,Str "code"]
+,Para [Code ("",[],[]) "*\8594*",Space,Code ("",[],[]) "typed",Space,Code ("",["haskell"],[]) ">>="]
+,Header 1 ("code-blocks",[],[]) [Str "code",Space,Str "blocks"]
+,CodeBlock ("",[],[]) "case xs of\n (_:_) -> reverse xs\n [] -> ['*']"
+,CodeBlock ("",["haskell"],[]) "case xs of\n (_:_) -> reverse xs\n [] -> ['*']"
+,Header 1 ("block-quotes",[],[]) [Str "block",Space,Str "quotes"]
+,Para [Str "Regular",Space,Str "paragraph"]
+,BlockQuote
+ [Para [Str "This",Space,Str "is",Space,Str "a",Space,Str "block",Space,Str "quote."]
+ ,Para [Str "With",Space,Str "two",Space,Str "paragraphs."]]
+,Para [Str "Nother",Space,Str "paragraph."]
+,Header 1 ("external-links",[],[]) [Str "external",Space,Str "links"]
+,Para [Link [Emph [Str "Google"],Space,Str "search",Space,Str "engine"] ("http://google.com","")]
+,Para [Link [Str "http://pandoc.org"] ("http://pandoc.org","")]
+,Para [Link [Str "http://google.com"] ("http://google.com",""),Space,Link [Str "http://yahoo.com"] ("http://yahoo.com","")]
+,Para [Link [Str "email",Space,Str "me"] ("mailto:info@example.org","")]
+,Para [Str "http://google.com"]
+,Para [Str "http://google.com"]
+,Para [Str "http://google.com"]
+,Para [Str "info@example.org"]
+,Para [Str "info@example.org"]
+,Para [Str "info@example.org"]
+,Header 1 ("lists",[],[]) [Str "lists"]
+,BulletList
+ [[Plain [Str "Start",Space,Str "each",Space,Str "line"]]
+ ,[Plain [Str "with",Space,Str "an",Space,Str "asterisk",Space,Str "(*)."]
+ ,BulletList
+ [[Plain [Str "More",Space,Str "asterisks",Space,Str "gives",Space,Str "deeper"]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "deeper",Space,Str "levels."]]]]]]
+ ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels."]]
+ ,[Plain [Str "Continuations",Space,Str "are",Space,Str "also",Space,Str "possible"]
+ ,BulletList
+ [[Plain [Str "and",Space,Str "do",Space,Str "not",Space,Str "break",Space,Str "the",Space,Str "list",Space,Str "flow"]]]]
+ ,[Plain [Str "Level",Space,Str "one"]]]
+,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "ends",Space,Str "the",Space,Str "list."]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "Start",Space,Str "each",Space,Str "line"]]
+ ,[Plain [Str "with",Space,Str "a",Space,Str "number",Space,Str "(1.)."]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "More",Space,Str "number",Space,Str "signs",Space,Str "gives",Space,Str "deeper"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "and",Space,Str "deeper"]]
+ ,[Plain [Str "levels."]]]]]]
+ ,[Plain [Str "Line",Space,Str "breaks",LineBreak,Str "don't",Space,Str "break",Space,Str "levels."]]
+ ,[Plain [Str "Blank",Space,Str "lines"]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "end",Space,Str "the",Space,Str "list",Space,Str "and",Space,Str "start",Space,Str "another."]]]
+,Para [Str "Any",Space,Str "other",Space,Str "start",Space,Str "also",Space,Str "ends",Space,Str "the",Space,Str "list."]
+,DefinitionList
+ [([Str "item",Space,Str "1"],
+ [[Plain [Str "definition",Space,Str "1"]]])
+ ,([Str "item",Space,Str "2"],
+ [[Plain [Str "definition",Space,Str "2-1",Space,Str "definition",Space,Str "2-2"]]])
+ ,([Str "item",Space,Emph [Str "3"]],
+ [[Plain [Str "definition",Space,Emph [Str "3"]]]])]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "one"]]
+ ,[Plain [Str "two"]
+ ,BulletList
+ [[Plain [Str "two",Space,Str "point",Space,Str "one"]]
+ ,[Plain [Str "two",Space,Str "point",Space,Str "two"]]]]
+ ,[Plain [Str "three"]
+ ,DefinitionList
+ [([Str "three",Space,Str "item",Space,Str "one"],
+ [[Plain [Str "three",Space,Str "def",Space,Str "one"]]])]]
+ ,[Plain [Str "four"]
+ ,DefinitionList
+ [([Str "four",Space,Str "def",Space,Str "one"],
+ [[Plain [Str "this",Space,Str "is",Space,Str "a",Space,Str "continuation"]]])]]
+ ,[Plain [Str "five"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "five",Space,Str "sub",Space,Str "1"]
+ ,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "five",Space,Str "sub",Space,Str "1",Space,Str "sub",Space,Str "1"]]]]
+ ,[Plain [Str "five",Space,Str "sub",Space,Str "2"]]]]]
+,OrderedList (1,DefaultStyle,DefaultDelim)
+ [[Plain [Str "other"]
+ ,OrderedList (1,UpperRoman,DefaultDelim)
+ [[Plain [Str "list"]]
+ ,[Plain [Str "styles"]]]]
+ ,[Plain [Str "are"]
+ ,OrderedList (1,LowerRoman,DefaultDelim)
+ [[Plain [Str "also"]]
+ ,[Plain [Str "possible"]]]]
+ ,[Plain [Str "all"]
+ ,OrderedList (1,LowerAlpha,DefaultDelim)
+ [[Plain [Str "the"]]
+ ,[Plain [Str "different"]]
+ ,[Plain [Str "styles"]]]]
+ ,[Plain [Str "are"]
+ ,OrderedList (1,UpperAlpha,DefaultDelim)
+ [[Plain [Str "implemented"]]
+ ,[Plain [Str "and"]]
+ ,[Plain [Str "supported"]]]]]
+,Header 1 ("tables",[],[]) [Str "tables"]
+,Table [] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ ,[[Plain [Str "Bread"]]
+ ,[Plain [Str "Pie"]]]
+ ,[[Plain [Str "Butter"]]
+ ,[Plain [Str "Ice",Space,Str "cream"]]]]
+,Table [] [AlignLeft,AlignLeft] [0.0,0.0]
+ [[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ [[[Plain [Str "Bread"]]
+ ,[Plain [Str "Pie"]]]
+ ,[[Plain [Strong [Str "Butter"]]]
+ ,[Plain [Str "Ice",Space,Str "cream"]]]]
+,Table [] [AlignLeft,AlignLeft] [0.0,0.0]
+ [[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]]
+ [[[Plain [Str "Bread",LineBreak,LineBreak,Str "and",Space,Str "cheese"]]
+ ,[Plain [Str "Pie",LineBreak,LineBreak,Strong [Str "apple"],Space,Str "and",Space,Emph [Str "carrot"]]]]]
+,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.0,0.0,0.0]
+ [[]
+ ,[]
+ ,[]]
+ [[[Plain [Str "Orange"]]
+ ,[Plain [Str "Apple"]]
+ ,[Plain [Str "more"]]]
+ ,[[Plain [Str "Bread"]]
+ ,[Plain [Str "Pie"]]
+ ,[Plain [Str "more"]]]
+ ,[[Plain [Str "Butter"]]
+ ,[Plain [Str "Ice",Space,Str "cream"]]
+ ,[Plain [Str "and",Space,Str "more"]]]]
+,Header 1 ("macros",[],[]) [Str "macros"]
+,Para [Span ("",["twiki-macro","TEST"],[]) []]
+,Para [Span ("",["twiki-macro","TEST"],[]) [Str ""]]
+,Para [Span ("",["twiki-macro","TEST"],[]) [Str "content with spaces"]]
+,Para [Span ("",["twiki-macro","TEST"],[]) [Str "content with spaces"]]
+,Para [Span ("",["twiki-macro","TEST"],[("ARG1","test")]) [Str "content with spaces"]]
+,Para [Span ("",["twiki-macro","TEST"],[]) [Str "content with spaces ARG1=test"]]
+,Para [Span ("",["twiki-macro","TEST"],[("ARG1","test")]) [Str "content with spaces"]]
+,Para [Span ("",["twiki-macro","TEST"],[("ARG1","test"),("ARG2","test2")]) [Str ""]]
+,Para [Span ("",["twiki-macro","TEST"],[("ARG1","test"),("ARG2","test2")]) [Str ""]]
+,Para [Span ("",["twiki-macro","TEST"],[("ARG1","test"),("ARG2","test2")]) [Str "multiline\ndoes also work"]]]
diff --git a/tests/twiki-reader.twiki b/tests/twiki-reader.twiki
new file mode 100644
index 000000000..c2df10573
--- /dev/null
+++ b/tests/twiki-reader.twiki
@@ -0,0 +1,221 @@
+---+ header
+
+---++ header level two
+
+---+++ header level 3
+
+---++++ header _level_ four
+
+---+++++ header level 5
+
+---++++++ header level 6
+
+---+++++++ not a header
+
+ --++ not a header
+
+---+ emph and strong
+
+_emph_ *strong*
+
+__strong and emph__
+
+*<i>emph inside</i> strong*
+
+*strong with <i>emph</i>*
+
+_<b>strong inside</b> emph_
+
+---+ horizontal rule
+
+top
+---
+bottom
+
+---
+
+---+ nop
+
+<nop>_not emph_
+
+---+ entities
+
+hi & low
+
+hi &amp; low
+
+G&ouml;del
+
+&#777;&#xAAA;
+
+---+ comments
+
+inline <!-- secret --> comment
+
+<!-- secret -->
+
+between blocks
+
+ <!-- secret -->
+
+---+ linebreaks
+
+hi%BR%there
+
+hi%BR%
+there
+
+---+ inline code
+
+<code>*→*</code> =typed= <code class="haskell">>>=</code>
+
+---+ code blocks
+
+<verbatim>
+case xs of
+ (_:_) -> reverse xs
+ [] -> ['*']
+</verbatim>
+
+<verbatim class="haskell">
+case xs of
+ (_:_) -> reverse xs
+ [] -> ['*']
+</verbatim>
+
+---+ block quotes
+
+Regular paragraph
+<blockquote>
+This is a block quote.
+
+With two paragraphs.
+</blockquote>
+Nother paragraph.
+
+---+ external links
+
+[[http://google.com][<i>Google</i> search engine]]
+
+http://pandoc.org
+
+[[http://google.com]] [[http://yahoo.com]]
+
+[[mailto:info@example.org][email me]]
+
+!http://google.com
+
+<nop>http://google.com
+
+<noautolink>
+http://google.com
+</noautolink>
+
+!info@example.org
+
+<nop>info@example.org
+
+<noautolink>
+info@example.org
+</noautolink>
+
+---+ lists
+
+ * Start each line
+ * with an asterisk (*).
+ * More asterisks gives deeper
+ * and deeper levels.
+ * Line breaks%BR%don't break levels.
+ * Continuations
+ are also possible
+ * and do not break the list flow
+ * Level one
+Any other start ends the list.
+
+ 1. Start each line
+ 1. with a number (1.).
+ 1. More number signs gives deeper
+ 1. and deeper
+ 1. levels.
+ 1. Line breaks%BR%don't break levels.
+ 1. Blank lines
+
+ 1. end the list and start another.
+Any other start also
+ends the list.
+
+ $ item 1: definition 1
+ $ item 2: definition 2-1
+ definition 2-2
+ $ item _3_: definition _3_
+
+ 1. one
+ 1. two
+ * two point one
+ * two point two
+ 1. three
+ $ three item one: three def one
+ 1. four
+ $ four def one: this
+ is a continuation
+ 1. five
+ 1. five sub 1
+ 1. five sub 1 sub 1
+ 1. five sub 2
+
+ 1. other
+ I. list
+ I. styles
+ 1. are
+ i. also
+ i. possible
+ 1. all
+ a. the
+ a. different
+ a. styles
+ 1. are
+ A. implemented
+ A. and
+ A. supported
+
+---+ tables
+
+|Orange|Apple|
+|Bread|Pie|
+|Butter|Ice cream|
+
+|*Orange*|*Apple*|
+|Bread|Pie|
+|*Butter*|Ice cream|
+
+|*Orange*|*Apple*|
+|Bread%BR%%BR%and cheese|Pie%BR%%BR%*apple* and <i>carrot</i>|
+
+| Orange | Apple | more |
+| Bread | Pie | more |
+| Butter | Ice cream | and more |
+
+---+ macros
+
+%TEST%
+
+%TEST{}%
+
+%TEST{content with spaces}%
+
+%TEST{"content with spaces"}%
+
+%TEST{"content with spaces" ARG1="test"}%
+
+%TEST{content with spaces ARG1=test}%
+
+%TEST{ARG1=test content with spaces}%
+
+%TEST{ARG1=test ARG2=test2}%
+
+%TEST{ARG1="test" ARG2="test2"}%
+
+%TEST{ARG1="test"
+ARG2="test2"
+multiline
+does also work}%
diff --git a/tests/writer.asciidoc b/tests/writer.asciidoc
index 4b063fe68..aebc529f0 100644
--- a/tests/writer.asciidoc
+++ b/tests/writer.asciidoc
@@ -375,15 +375,19 @@ HTML Blocks
Simple block on one line:
foo
+
And nested without indentation:
foo
bar
+
Interpreted markdown in a table:
This is _emphasized_
+
And this is *strong*
+
Here’s a simple block:
foo
@@ -405,6 +409,7 @@ As should this:
Now, nested:
foo
+
This should just be an HTML comment:
Multiline:
@@ -485,7 +490,7 @@ Ellipses…and…and….
LaTeX
-----
-*
+*
* latexmath:[$2+2=4$]
* latexmath:[$x \in y$]
* latexmath:[$\alpha \wedge \omega$]
diff --git a/tests/writer.context b/tests/writer.context
index 244463f93..29af26dba 100644
--- a/tests/writer.context
+++ b/tests/writer.context
@@ -25,7 +25,7 @@
\definedescription
[description]
- [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm]
+ [headstyle=bold, style=normal, location=hanging, width=broad, margin=1cm, alternative=hanging]
\setupitemize[autointro] % prevent orphan list intro
\setupitemize[indentnext=no]
diff --git a/tests/writer.dokuwiki b/tests/writer.dokuwiki
index 704e79b87..fe1f8296a 100644
--- a/tests/writer.dokuwiki
+++ b/tests/writer.dokuwiki
@@ -36,7 +36,8 @@ In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Beca
Here’s one with a bullet. * criminey.
-There should be a hard line break\\ here.
+There should be a hard line break\\
+here.
----
@@ -50,9 +51,11 @@ E-mail style:
<HTML><blockquote>
Code in a block quote:
-<code>sub status {
+<code>
+sub status {
print "working";
-}</code>
+}
+</code>
A list:
- item one
@@ -75,18 +78,22 @@ And a following paragraph.
Code:
-<code>---- (should be four hyphens)
+<code>
+---- (should be four hyphens)
sub status {
print "working";
}
-this code block is indented by one tab</code>
+this code block is indented by one tab
+</code>
And:
-<code> this code block is indented by two tabs
+<code>
+ this code block is indented by two tabs
-These should not be escaped: \$ \\ \> \[ \{</code>
+These should not be escaped: \$ \\ \> \[ \{
+</code>
----
@@ -267,8 +274,11 @@ Multiple blocks with italics:
<HTML><p></HTML>contains seeds, crisp, pleasant to taste<HTML></p></HTML><HTML></dd></HTML>
<HTML><dt></HTML>//orange//<HTML></dt></HTML>
<HTML><dd></HTML><HTML><p></HTML>orange fruit<HTML></p></HTML>
-<code>{ orange code block }</code>
-> <HTML><p></HTML>orange block quote<HTML></p></HTML><HTML></dd></HTML><HTML></dl></HTML>
+<code>
+{ orange code block }
+</code>
+> <HTML><p></HTML>orange block quote<HTML></p></HTML>
+<HTML></dd></HTML><HTML></dl></HTML>
Multiple definitions, tight:
@@ -328,12 +338,16 @@ foo
This should be a code block, though:
-<code><div>
+<code>
+<div>
foo
-</div></code>
+</div>
+</code>
As should this:
-<code><div>foo</div></code>
+<code>
+<div>foo</div>
+</code>
Now, nested:
foo
@@ -358,7 +372,9 @@ Blah
</HTML>
Code block:
-<code><!-- Comment --></code>
+<code>
+<!-- Comment -->
+</code>
Just plain comment, with trailing spaces on the line:
<HTML>
@@ -366,7 +382,9 @@ Just plain comment, with trailing spaces on the line:
</HTML>
Code:
-<code><hr /></code>
+<code>
+<hr />
+</code>
Hr’s:
<HTML>
@@ -436,13 +454,13 @@ Ellipses…and…and….
====== LaTeX ======
*
- * <math>2+2=4</math>
- * <math>x \in y</math>
- * <math>\alpha \wedge \omega</math>
- * <math>223</math>
- * <math>p</math>-Tree
- * Here’s some display math: <math>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
- * Here’s one that has a line break in it: <math>\alpha + \omega \times x^2</math>.
+ * $2+2=4$
+ * $x \in y$
+ * $\alpha \wedge \omega$
+ * $223$
+ * $p$-Tree
+ * Here’s some display math: $\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$
+ * Here’s one that has a line break in it: $\alpha + \omega \times x^2$.
These shouldn’t be math:
@@ -554,7 +572,9 @@ Indented [[url|thrice]].
This should [not][] be a link.
-<code>[not]: /url</code>
+<code>
+[not]: /url
+</code>
Foo [[url/|bar]].
Foo [[url/|biz]].
@@ -583,7 +603,9 @@ An e-mail address: <nobody@nowhere.net>
Auto-links should not occur here: ''%%<http://example.com/>%%''
-<code>or here: <http://example.com/></code>
+<code>
+or here: <http://example.com/>
+</code>
----
@@ -605,13 +627,15 @@ Here is a footnote reference,((Here is the footnote. It can go anywhere after th
Subsequent blocks are indented to show that they belong to the footnote (as with list items).
-<code> { <code> }</code>
+<code>
+ { <code> }
+</code>
If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.
)) This should //not// be a footnote reference, because it contains a space.[^my note] Here is an inline note.((This is //easier// to type. Inline notes may contain [[http://google.com|links]] and ''%%]%%'' verbatim characters, as well as [bracketed text].
))
> Notes can go in quotes.((In quote.
-))
+> ))
- And in list items.((In list.))
diff --git a/tests/writer.fb2 b/tests/writer.fb2
index ce00cbef3..8cc271deb 100644
--- a/tests/writer.fb2
+++ b/tests/writer.fb2
@@ -1,2 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
-<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><book-title>Pandoc Test Suite</book-title><author><first-name>John</first-name><last-name>MacFarlane</last-name></author><author><nickname>Anonymous</nickname></author><date>July 17, 2006</date></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p>Pandoc Test Suite</p></title><annotation><p>John MacFarlane</p><p>Anonymous</p><p>July 17, 2006</p></annotation><section><p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Headers</p></title><section><title><p>Level 2 with an embedded link &lt;/url&gt;</p></title><section><title><p>Level 3 with emphasis</p></title><section><title><p>Level 4</p></title><section><title><p>Level 5</p></title></section></section></section></section></section><section><title><p>Level 1</p></title><section><title><p>Level 2 with emphasis</p></title><section><title><p>Level 3</p></title><p>with no blank line</p></section></section><section><title><p>Level 2</p></title><p>with no blank line</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Paragraphs</p></title><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<empty-line />here.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Block Quotes</p></title><p>E-mail style:</p><cite><p>This is a block quote. It is pretty short.</p></cite><cite><p>Code in a block quote:</p><empty-line /><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><empty-line /><p>A list:</p><p> 1. item one</p><p> 2. item two</p><p>Nested block quotes:</p><cite><p>nested</p></cite><cite><p>nested</p></cite></cite><p>This should not be a block quote: 2 &gt; 1.</p><p>And a following paragraph.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Code Blocks</p></title><p>Code:</p><empty-line /><p><code>---- (should be four hyphens)</code></p><p><code></code></p><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><p><code></code></p><p><code>this code block is indented by one tab</code></p><empty-line /><p>And:</p><empty-line /><p><code> this code block is indented by two tabs</code></p><p><code></code></p><p><code>These should not be escaped: \$ \\ \&gt; \[ \{</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Lists</p></title><section><title><p>Unordered</p></title><p>Asterisks tight:</p><p>• asterisk 1</p><p>• asterisk 2</p><p>• asterisk 3</p><p>Asterisks loose:</p><p>• asterisk 1<empty-line /></p><p>• asterisk 2<empty-line /></p><p>• asterisk 3<empty-line /></p><p>Pluses tight:</p><p>• Plus 1</p><p>• Plus 2</p><p>• Plus 3</p><p>Pluses loose:</p><p>• Plus 1<empty-line /></p><p>• Plus 2<empty-line /></p><p>• Plus 3<empty-line /></p><p>Minuses tight:</p><p>• Minus 1</p><p>• Minus 2</p><p>• Minus 3</p><p>Minuses loose:</p><p>• Minus 1<empty-line /></p><p>• Minus 2<empty-line /></p><p>• Minus 3<empty-line /></p></section><section><title><p>Ordered</p></title><p>Tight:</p><p> 1. First</p><p> 2. Second</p><p> 3. Third</p><p>and:</p><p> 1. One</p><p> 2. Two</p><p> 3. Three</p><p>Loose using tabs:</p><p> 1. First<empty-line /></p><p> 2. Second<empty-line /></p><p> 3. Third<empty-line /></p><p>and using spaces:</p><p> 1. One<empty-line /></p><p> 2. Two<empty-line /></p><p> 3. Three<empty-line /></p><p>Multiple paragraphs:</p><p> 1. Item 1, graf one.<empty-line />Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.<empty-line /></p><p> 2. Item 2.<empty-line /></p><p> 3. Item 3.<empty-line /></p></section><section><title><p>Nested</p></title><p>• Tab<p>◦ Tab<p>* Tab</p></p></p><p>Here’s another:</p><p> 1. First</p><p> 2. Second:<p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third</p><p>Same thing but with paragraphs:</p><p> 1. First<empty-line /></p><p> 2. Second:<empty-line /><p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third<empty-line /></p></section><section><title><p>Tabs and spaces</p></title><p>• this is a list item indented with tabs<empty-line /></p><p>• this is a list item indented with spaces<empty-line /><p>◦ this is an example list item indented with tabs<empty-line /></p><p>◦ this is an example list item indented with spaces<empty-line /></p></p></section><section><title><p>Fancy list markers</p></title><p> (2) begins with 2</p><p> (3) and now 3<empty-line />with a continuation<empty-line /><p> (3) iv. sublist with roman numerals, starting with 4</p><p> (3) v. more items<p> (3) v. (A) a subsublist</p><p> (3) v. (B) a subsublist</p></p></p><p>Nesting:</p><p> A. Upper Alpha<p> A. I. Upper Roman.<p> A. I. (6) Decimal start with 6<p> A. I. (6) c) Lower alpha with paren</p></p></p></p><p>Autonumbering:</p><p> 1. Autonumber.</p><p> 2. More.<p> 2. 1. Nested.</p></p><p>Should not be a list item:</p><p>M.A. 2007</p><p>B. Williams</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Definition Lists</p></title><p>Tight using spaces:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Tight using tabs:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Multiple blocks with italics:</p><p><strong><emphasis>apple</emphasis></strong></p><p>    red fruit<empty-line />    contains seeds, crisp, pleasant to taste<empty-line /></p><p><strong><emphasis>orange</emphasis></strong></p><p>    orange fruit<empty-line /><empty-line /><p><code>    { orange code block }</code></p><empty-line /><cite><p>    orange block quote</p></cite></p><p>Multiple definitions, tight:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Multiple definitions, loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Blank line after term, indented marker, alternate markers:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /><p> 1. sublist</p><p> 2. sublist</p></p></section><section><title><p>HTML Blocks</p></title><p>Simple block on one line:</p>foo<p>And nested without indentation:</p><p>foo</p>bar<p>Interpreted markdown in a table:</p><empty-line /><p><code>&lt;table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />This is <emphasis>emphasized</emphasis><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />And this is <strong>strong</strong><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;script type=&quot;text/javascript&quot;&gt;document.write(&#39;This *should not* be interpreted as markdown&#39;);&lt;/script&gt;</code></p><empty-line /><p>Here’s a simple block:</p><p>foo</p><p>This should be a code block, though:</p><empty-line /><p><code>&lt;div&gt;</code></p><p><code> foo</code></p><p><code>&lt;/div&gt;</code></p><empty-line /><p>As should this:</p><empty-line /><p><code>&lt;div&gt;foo&lt;/div&gt;</code></p><empty-line /><p>Now, nested:</p>foo<p>This should just be an HTML comment:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Multiline:</p><empty-line /><p><code>&lt;!--</code></p><p><code>Blah</code></p><p><code>Blah</code></p><p><code>--&gt;</code></p><empty-line /><empty-line /><p><code>&lt;!--</code></p><p><code> This is another comment.</code></p><p><code>--&gt;</code></p><empty-line /><p>Code block:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Just plain comment, with trailing spaces on the line:</p><empty-line /><p><code>&lt;!-- foo --&gt;</code></p><empty-line /><p>Code:</p><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><p>Hr’s:</p><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Inline Markup</p></title><p>This is <emphasis>emphasized</emphasis>, and so <emphasis>is this</emphasis>.</p><p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p><p>An <emphasis>emphasized link<a l:href="#l1" type="note"><sup>[1]</sup></a></emphasis>.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p><p><strikethrough>This is <emphasis>strikeout</emphasis>.</strikethrough></p><p>Superscripts: a<sup>bc</sup>d a<sup><emphasis>hello</emphasis></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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Smart quotes, ellipses, dashes</p></title><p>“Hello,” said the spider. “‘Shelob’ is my name.”</p><p>‘A’, ‘B’, and ‘C’ are letters.</p><p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p><p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p><p>Here is some quoted ‘<code>code</code>’ and a “quoted link<a l:href="#l2" type="note"><sup>[2]</sup></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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>LaTeX</p></title><p>• </p><p>• <code>2+2=4</code></p><p>• <code>x \in y</code></p><p>• <code>\alpha \wedge \omega</code></p><p>• <code>223</code></p><p>• <code>p</code>-Tree</p><p>• Here’s some display math: <code>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</code></p><p>• Here’s one that has a line break in it: <code>\alpha + \omega \times x^2</code>.</p><p>These shouldn’t be math:</p><p>• To get the famous equation, write <code>$e = mc^2$</code>.</p><p>• $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It worked if “lot” is emphasized.)</p><p>• Shoes ($20) and socks ($5).</p><p>• Escaped <code>$</code>: $73 <emphasis>this should be emphasized</emphasis> 23$.</p><p>Here’s a LaTeX table:</p><empty-line /><p><code>\begin{tabular}{|l|l|}\hline</code></p><p><code>Animal &amp; Number \\ \hline</code></p><p><code>Dog &amp; 2 \\</code></p><p><code>Cat &amp; 1 \\ \hline</code></p><p><code>\end{tabular}</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Special Characters</p></title><p>Here is some unicode:</p><p>• I hat: Î</p><p>• o umlaut: ö</p><p>• section: §</p><p>• set membership: ∈</p><p>• copyright: ©</p><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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Links</p></title><section><title><p>Explicit</p></title><p>Just a URL<a l:href="#l3" type="note"><sup>[3]</sup></a>.</p><p>URL and title<a l:href="#l4" type="note"><sup>[4]</sup></a>.</p><p>URL and title<a l:href="#l5" type="note"><sup>[5]</sup></a>.</p><p>URL and title<a l:href="#l6" type="note"><sup>[6]</sup></a>.</p><p>URL and title<a l:href="#l7" type="note"><sup>[7]</sup></a></p><p>URL and title<a l:href="#l8" type="note"><sup>[8]</sup></a></p><p>with_underscore<a l:href="#l9" type="note"><sup>[9]</sup></a></p><p>Email link<a l:href="#l10" type="note"><sup>[10]</sup></a></p><p>Empty<a l:href="#l11" type="note"><sup>[11]</sup></a>.</p></section><section><title><p>Reference</p></title><p>Foo bar<a l:href="#l12" type="note"><sup>[12]</sup></a>.</p><p>Foo bar<a l:href="#l13" type="note"><sup>[13]</sup></a>.</p><p>Foo bar<a l:href="#l14" type="note"><sup>[14]</sup></a>.</p><p>With embedded [brackets]<a l:href="#l15" type="note"><sup>[15]</sup></a>.</p><p>b<a l:href="#l16" type="note"><sup>[16]</sup></a> by itself should be a link.</p><p>Indented once<a l:href="#l17" type="note"><sup>[17]</sup></a>.</p><p>Indented twice<a l:href="#l18" type="note"><sup>[18]</sup></a>.</p><p>Indented thrice<a l:href="#l19" type="note"><sup>[19]</sup></a>.</p><p>This should [not][] be a link.</p><empty-line /><p><code>[not]: /url</code></p><empty-line /><p>Foo bar<a l:href="#l20" type="note"><sup>[20]</sup></a>.</p><p>Foo biz<a l:href="#l21" type="note"><sup>[21]</sup></a>.</p></section><section><title><p>With ampersands</p></title><p>Here’s a link with an ampersand in the URL<a l:href="#l22" type="note"><sup>[22]</sup></a>.</p><p>Here’s a link with an amersand in the link text: AT&amp;T<a l:href="#l23" type="note"><sup>[23]</sup></a>.</p><p>Here’s an inline link<a l:href="#l24" type="note"><sup>[24]</sup></a>.</p><p>Here’s an inline link in pointy braces<a l:href="#l25" type="note"><sup>[25]</sup></a>.</p></section><section><title><p>Autolinks</p></title><p>With an ampersand: http://example.com/?foo=1&amp;bar=2<a l:href="#l26" type="note"><sup>[26]</sup></a></p><p>• In a list?</p><p>• http://example.com/<a l:href="#l27" type="note"><sup>[27]</sup></a></p><p>• It should.</p><p>An e-mail address: nobody@nowhere.net<a l:href="#l28" type="note"><sup>[28]</sup></a></p><cite><p>Blockquoted: http://example.com/<a l:href="#l29" type="note"><sup>[29]</sup></a></p></cite><p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p><empty-line /><p><code>or here: &lt;http://example.com/&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Images</p></title><p>From “Voyage dans la Lune” by Georges Melies (1902):</p><image l:href="#image1" l:type="imageType" alt="lalune" title="Voyage dans la Lune" /><p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Footnotes</p></title><p>Here is a footnote reference,<a l:href="#n30" type="note"><sup>[30]</sup></a> and another.<a l:href="#n31" type="note"><sup>[31]</sup></a> This should <emphasis>not</emphasis> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a l:href="#n32" type="note"><sup>[32]</sup></a></p><cite><p>Notes can go in quotes.<a l:href="#n33" type="note"><sup>[33]</sup></a></p></cite><p> 1. And in list items.<a l:href="#n34" type="note"><sup>[34]</sup></a></p><p>This paragraph should not be part of the note, as it is not indented.</p></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>/url</code></p></section><section id="l2"><title><p>2</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l3"><title><p>3</p></title><p><code>/url/</code></p></section><section id="l4"><title><p>4</p></title><p>title: <code>/url/</code></p></section><section id="l5"><title><p>5</p></title><p>title preceded by two spaces: <code>/url/</code></p></section><section id="l6"><title><p>6</p></title><p>title preceded by a tab: <code>/url/</code></p></section><section id="l7"><title><p>7</p></title><p>title with &quot;quotes&quot; in it: <code>/url/</code></p></section><section id="l8"><title><p>8</p></title><p>title with single quotes: <code>/url/</code></p></section><section id="l9"><title><p>9</p></title><p><code>/url/with_underscore</code></p></section><section id="l10"><title><p>10</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l11"><title><p>11</p></title><p><code></code></p></section><section id="l12"><title><p>12</p></title><p><code>/url/</code></p></section><section id="l13"><title><p>13</p></title><p><code>/url/</code></p></section><section id="l14"><title><p>14</p></title><p><code>/url/</code></p></section><section id="l15"><title><p>15</p></title><p><code>/url/</code></p></section><section id="l16"><title><p>16</p></title><p><code>/url/</code></p></section><section id="l17"><title><p>17</p></title><p><code>/url</code></p></section><section id="l18"><title><p>18</p></title><p><code>/url</code></p></section><section id="l19"><title><p>19</p></title><p><code>/url</code></p></section><section id="l20"><title><p>20</p></title><p>Title with &quot;quotes&quot; inside: <code>/url/</code></p></section><section id="l21"><title><p>21</p></title><p>Title with &quot;quote&quot; inside: <code>/url/</code></p></section><section id="l22"><title><p>22</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l23"><title><p>23</p></title><p>AT&amp;T: <code>http://att.com/</code></p></section><section id="l24"><title><p>24</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l25"><title><p>25</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l26"><title><p>26</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l27"><title><p>27</p></title><p><code>http://example.com/</code></p></section><section id="l28"><title><p>28</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l29"><title><p>29</p></title><p><code>http://example.com/</code></p></section><section id="n30"><title><p>30</p></title><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</p></section><section id="n31"><title><p>31</p></title><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><empty-line /><p><code> { &lt;code&gt; }</code></p><empty-line /><p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</p></section><section id="n32"><title><p>32</p></title><p>This is <emphasis>easier</emphasis> to type. Inline notes may contain links<a l:href="#l32" type="note"><sup>[32]</sup></a> and <code>]</code> verbatim characters, as well as [bracketed text].</p></section><section id="n33"><title><p>33</p></title><p>In quote.</p></section><section id="n34"><title><p>34</p></title><p>In list.</p></section></body><binary id="image2" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEASABIAAD//gBQVGhpcyBhcnQgaXMgaW4gdGhlIHB1YmxpYyBkb21haW4uIEtldmluIEh1Z2hlcywga2V2aW5oQGVpdC5jb20sIFNlcHRlbWJlciAxOTk1/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAFgAUAwEiAAIRAQMRAf/EABoAAQACAwEAAAAAAAAAAAAAAAAICQUGCgf/xAAjEAABBQEAAwABBQAAAAAAAAAGAwQFBwgCAAEJChEVOXa3/8QAFgEBAQEAAAAAAAAAAAAAAAAABggA/8QAJhEBAAECBQEJAAAAAAAAAAAAAQIAAwQFBhEhszE0NlFUcXR1tP/aAAwDAQACEQMRAD8AqQzziPNmpiqnIO1q4H+WkB84MdlzRSuM82/jVw/JCORtRmQz5d2VTy6WmS2eSYx3U/qkSRbgFsqRzH2Is4/mCluXc33vy8xTnJjTNqV/T8LKmkhr8Hq1da2aOvTfIh2CFeNt+GxFBP8AJFdFUbPWh+4FdXV7OtZOMR7mK9lBWNN+JBmMQ5cwmfH8DEFhTZUCRlE6CBq/ds/nBh9oYygeY1L9FnCUnBSN1t+w0l9bNomx1cllsOrL9OCTKtKOIqua6UVjP0dEvTyM7gp/3whbkAD0ScX3r6MLg+C2/XsMhCnJRn/5cVNHyJHiX6JKIFhhqnFeagm9BIgjfcJyNBTZiROBUk6Mp8CJRmT4NWU2MatV7n495DPk/wAbMJSRJOTBDItq0KR5s/nJN7LPW8AJWtYAoKQaDp+u4XShxgXhYcbHoxNTllCwETGQ8ag2jmDVsk8w/wCOp/C/hn+mWV/utpePH+D5wmF39NY6UakjUYR1Dn0YgRM5zQAAAMdfAA4AOAOArjkMNQ3vgm7UKtBR+m9QHFD5tpnDtpy+t2R20gK/OsmFtuDpaL5mVyiT5qdEVAvZci5ch5VoSGKbwlWTBr0RPoZT07av9lHfrXo6yLApWMugKpPM9SV1cDm65s/wkOHZBojoqiM+6GpMSj4FhtayNAUi5H3LfQBG2KWssFoSPuJdKyMLKtpuLi+e3jwFICUg7CSHsNVlYlKdizOTvKdq3KTsG8pQirsAG6vAB5FdhP490U4gfjxi+DedoqO4YftmKdKNulO26jiOv+2Ga/bftVNFXpHtVHrpLpRFJTpP3z77T469++fTx48e4LueE+NY6UKk7UniLP8A7rNf3X6//9k=</binary><binary id="image1" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAD6APoDAREAAhEBAxEB/8QAHAAAAAcBAQAAAAAAAAAAAAAAAQIDBAUGBwAI/8QAPhAAAgEDAwIEBAQFAgUFAAMAAQIDAAQRBRIhBjETIkFRB2FxgRQykaEjQlKxwRXwFjNictEIJEPh8SZTgv/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgT/xAAbEQEBAQEAAwEAAAAAAAAAAAAAARECEiExQf/aAAwDAQACEQMRAD8A2t0YoQpwT2qVzMV+N3UHgrDY2eoM0y58VEbgfp9K1yMRmnuJ5h40jyYHGSeKrWE8u2QAApOMdqGCsmT8h70TAJwMAZx249aKBy4c9vTNUC0zDCgmmmG7Ockjkj1PrUTAjcy5XP0ouCgHae4IomOJHhgIc55PHY0Uk5IXLMcUBQ27n96JYO2MYLebHtRBA7BcMx29sdxQJqwZRtIP+BQKpjHHc+xzigNGoAO/k+nPAoAYlee5oBiGeWySO9AJCgY5PHagFCADzj2GaA2N2TkjA/U0HMwbPPeiyBLDfkkj04FCl1cBMgn6URwYFGySR6D2oAeQDAxnHGKAhU4IbGc+tFwnwDj9aK7f8v2oNu+IHxNvJdXmt9EmKWSqArA/mPvxUxMZNe3Ml1dvNcMzSSEsxPOferJhht/OWyAPc0UfdgDcuM8n50AMCykZFARsngcY/egTcbjnJz9O9AB2kZGSQOcUCX8x83bntQCMruJ4B7D1oCyOGzxtJ9M80CAdg5UjFE0aFJrghLeNpHY4IRdx/QUNWCw6D6q1EZttEvirHAZ4ig/U4qw1b9H+CHVN3Mq6hJaWMJ5ZjJ4hA/7R3P3q3ET+pf8Ap/lWNm03XkkkA8qTW+3PHupP9qxopV78G+s7VSV0+OcAn/kzqSfscVvIKzqPTWu6XKE1LSL+Bhz5oDg/cd6lEZzGwLrtPqrA8frUCJfcw9gfegUjZsEAffNADyHt78UAjCjzDJxRcO5Pw3gwCGOVJQp8ZncMGOeNoxwMY96GCbQffFFcUXKjDDt2NEo+N3yyM5z3okKuqJgIzONoJyuMGi4QfGcqSfXBoYHJx659qKIRnnsfUGgJn/poJYoTIGLY+eDzQFlQK2G/KCTmgbspfO0qce/agPGcR7nHf9vnQFfBPlOc88Gg7uucc/M0Bd208YJJweKAYrea4kKQICRGW5IUYUZJ570DYqcknt3FE0VuVyDzj1oamOlulda6puvC0a0eZVIWSbtGn1Y1NNbX0x8ENH0qL8X1NdtqDoNxiQbIh8u+WpqL70Tc6fcxypouiRadbW8hhLFFXcB7Edz+tNFvEZxkmmgShbA9PlUA+Hgg/wBqDgmBkd6ArJuJBGR7VdEdqWgaVqMfh6hp9pcLj/5Ig2KaKJrvwW6S1EFoLaWwmPIe2fAz81ORTRm3UfwI1mzBbRL+K/ReyS/w3x/b+1Wexmev9O6xoE2zWdOubUDszr5T9G7H9auCJj2n3PPrUXTlGBB2kYx96GlQMjJJHuRRXBgDgk8DtRKH8w4OfYA0SUlIMsFXJ4oujHH8ufnRRGOSNoJNAeFC77F2jPucfvQFEqgY3nj/AKaCUY58wwq54AoCzOmVMke9QeRnGR7ZoEIF7pnaTk49KDpSSwQntQJsGKjgggZ9uDQc4OOe1Am2UCkHOR7dqA8t/cSW8MEkrGGEsUTPCk4zj9KJT3pzQtS6m1aPT9Jh8SVxlmJwqL/UfYURuuhfArR7f8NLrF1cXciKDJCrbI2b7c4+9NGtaRptrpdqltYW0VtAn5Y41wBUodvGjqUdQyn0YZqAIreOBFSFFRF7BQAKA1xcRwKplcJuOBn1NAR7y2ikWMzoZnGVQHJNAuQcD3oBKkD2FBy8jnvQFxnjjmg4rxwKBMqCBtPNA3vbCC+tngvYo54HGGSRQQR9DV0Y91n8DNOvFkuOmZmsrk5PgSNuiY98D1X+1XRhWu6DqWgX72er2j2069t/ZvmD2IoGG7jbnj1FFlB224PB+VClN4DYJHyAojmPGCck8cetCAxgjPp6UaAGKtx6+9ATAXO7nFBw8HHLN+goJhBuj2FeAcnmgNazW8U0vjweODGyqpYrsYjytx3x3oGa5LEEjH9XvQGlgmjjMmQq4HBPfPYgevagG5nhe3tkFuInQHxJQTmQntn0wKBKTlAeDx60DSY+U9zn+mgsnQvROr9Y3W2xi8KxV8SXUnCrjvj1Y/IUR6c6A6H03o6wMVgrSXMoBmuX/NIf8Djt/eiLfjJwO9ZBiOfmKDhktzQAzYBLZ8oyaDF+rOptVv8AUjNZL4tjA/lT+kr3wvqTQX/pi3Y+DqFxKXurmFWAaPaVzg4I/b0oHlxqV7penRTXFu93dPLsESYB2k8n7CgnradLq1WaIOFI/K42sPkRQCg3Kcd6Dgp3d6AdrGg5VxnjmgKWB8uQGxnFAUgKuSefSghuqNC0jXbAWGtxQyJKdsYc4YMf6T6GtDzR8S/hnqfSUz3NvuvNILYSZR5o+ezj/Pb6UGfLzyD/AJoFFySQVBHpQDJ5kGByPahAbWxn5+po0OF3D+XPtQJsNwOe+aAuygmMkebgHnHFALHYpJwSeGz2oGpOJWAI49BQEZlYAHkg4oARVOMvtBIJJ7AUAX6xxSOsUgmjViFcKRuHviiVfvhT8NZuqpk1LVFeHRkPlHZpznsP+n50qPS+mWVppdnFa2cEcFtGu1I41ChR8qyHVxK8cLPDD4kgGVQHBNAa0maaBJGTYzDJXOcUCy5JOaA2OMfoaArkheM7vlQNYNOtoWLJCgLHJwo5NApPKLaNpGRQB6j2oGmnRvcyNd3O/DkeErLhkWgklIdCyZOCRzxzQEeRxhdpUnncBkD5UCxXjJ7+tAlctMsIMLohz5mcZAH09aBQYdQwyAeaAuA7MAQxHH0oG1481nbGVInuWU5Kr+bHrgepoKB1u+o6jqlvBH05NevEBPBK0pQR4I4BHZj+1Bb9IS7lsFtNWtYwDGFYB/EXHqpJ7/WtQYx8VfhGbdZtV6Uh8gy81mpyR6koPb5UGKY4YkeYd88fbFAI5AC98c5oQBb+U9+9GnN5RgDgjOPWgAN3yMfWgAqc91/UUD2RSSRg9+49KCR6e0WfX9WS0icRwgb55WOFijH5nP0FBYNRi6dSR7HRNPmu0hOW1GaXaZMdwBwAP3oynE0XRYrFtV02wS4ECj8dp1wcsE7eJEf39qlFZ616ZttPu7Kbp9Zbi0vYzNCcgjHqoHuKsEp8LPh7P1PqjXerxywaXaviRSu1pWH8g+XuflQemIIY7S3SK3hVIo12pGoAAA7AClEL1N1RH0/oTalcwx+IACLaSQKx59Ppmshv0D1jH1ZbTubU27xkkAnKsuSMg/UUFluLlLaJXETyecKAg554zigXiubeRnSKeJ5FOGVXBIPsaBLULoWkIfw3kYsAqIOSTQJMbpm3oqlmwACeF9yfn+1A+Bx34oE5IY5P+YFbnPIzQKAckHuRQCAQOO1AL8r9KDhkZOT9M8UCcrxgAyYJzwD70CT3Itxm8kgi3fly+P7/AOKA9pskhEkZysnOfeg6RH8w3tgjAHtQRZ1uystSg0m5eRJ2UbHceV8fP3oJkBSAVII9xQFdSRwKDDvjN8L/AMSJte6chxcgFrm1QcSf9aj39x61YMH8Q+CkfhqpQncxBDH5H6VRwXJ/Ke1Am2QchuMYOaNFSAVznB9qAm8f10D2RmX8jDHP3oLbebtA6ej0m2LrfX6LcX7IMskf8kf6HcffIoG8yTadZxSTxCK3kRZUwSFfkruIJ78GhiS6Y1OS3160uZJFWO5bwZtxzuQ8bcfPNMZXvo2wsLnQ9R0q/maJNNv5Yo3bjCuMAHPzqA2jdUan0lF0/ZXcElxp9zE+5WVd/DE71IPPB7H2po1bSNXsdYthLp1ykyEcj+ZT817ioITrnoux6vs1gv5JYnjz4ckZ/Ln5etA+6N0BemdBttMina4WEFfFdQpIJJ7D60E5I4Vo9qnnsQO1A3k0yzeTxhCizZJ3qNpz9RQO449igMSxHGW5NAIwBtUAUAMORkfegMhG3jtQD8+fvQGXJz7UAHuRQA5YDI5FB0qCQA5yaCs2/SFit/Jd3AmvJ2bO64ctt5zwD2oLMilVAUDgcAelAJLbhgZz3oGN9HPIYmhtrWRw2czjt7Y+dA+h3mJS67W9gc0AvuLYANADpkZABHY85oPOnxy+Hx06Z+odGjC2jt/7qBRwjH+cY9D6/OrKMebcceHwfaqCYIyDgZ96GhHOFJI4/WjQpXnsaCz9J6fDqGvRC8OLO3Vri5PB/hqMkfc4H3oDT3UupapcXrKS9zISgDdhnAGPbsKC5aLLBHq9p01c6bbagPE23kpJYhmz5IySAAMj6nNGdRnT2lu3V9vaQQrJDHfCMFj5kAfufsMUFogu5H0jrLUYXK+Lq0aRse/lf/8AOKlFfudagvbnQpNQRmtILydCwPdCQcgMOMZFQanPoeiawBd9M6s9jeKPK1vKQp+RFA4septa6fuFtuqbRrmzx5b+BAdo927A+vsflQXfTr2z1O3W5025juIW/mjOR9KAZI914khaRNo4XdwT9KAl3b2+oWpjMoZWbOVfnI9sUCrXUNssUU8w3sQoJH5jQLvwQQC3NAKvuUPtK54waDg23v6UA7weBnNAIOBigMr+hoOjdZQdhBx3waAVG0Z7UBWfAOQSflQChyNxBAxQRutarb6bHALi9trSW4kEcJnGd7ewFA/j8QEK/IA/MBjmgWDDBB7igj9dupLTTbiaHZ4oQ7A7bQW9ATVgwXSNV6onl8azW6t45pWdxHIxWA/zNtz7A8Glg2S1u7fX+nt0J/H2c4MMhmQoW9GBUjj60g8sfEHpebpDqi4sHLG2Y77eQ486E8fcdvtVFekGW4UfegKVAAKgnFGhuDzxQXbpDTZF6a13UnUqrCOzQ5wGZmXIJ+lE0ppkEK6nJcRWcTW9hA08iKcjcowpye/mxQ0+6VRbC/jvLm48L8LG9y8pIOXxkDnuSTipqHXQMng3es9S3fhn8DbvcZI5Mr/lH700dc3Dad8NtPs4nU6jeXD6nMCwBRF5XOfU8YHrTNJFF1X8RawW1jc4GxTKNrZB385yPkBTFw1stSu7Ni9tPLGSQfK5Aphi8J8UNUm6fn0u72yvJ5fGbuF/39aYYtGgadp9/axXnRetzaXqnhqZI3bEcj4547Ak/X6UxFisPiXe6NMdO65057eQAr+LhUlHHbOPX07UwWXpQ6BqMo1LpgW0sioVI8Qgxk+684qC028M5890Y3kHKbUwF+lA4LDOzu2M4FAOG3DaoI9cntQdJxzQEyR259f/AKoGl5fSQRFo7ZpB/MhYIR9zxQdayyXKb7gqox5Yo2yB9WHc0DPUIWnhWKxkuYFRs5gcKWbPY59KBkx6isVeSGW31JNwHhyOUkA+o8v9qCfjkMo/LJFKqBmRvSgc2swnRyFcYODuXGfpQMtRsLK8vYJL+wjuGiUtHK6hghz6Z7H6UEmCsig84I9RigiruC9t0DaaVmIIHhTOQMeuGwT9qCJ1ywv9T0U29xFFiaVBJGHz5M5ODgYPY/arKJPTtLW1t44i7SKq48w8x+ZPrTRJoipGFQAAdgKgzX47dMJrXSrXkUe6807MykDkp/MP8/aro80FQyZ+tUJ7hvH0x270XQ7KGtXvIk0T4c9P2bIhkvpnvJVfjIxhf7qftRDXpu0/1DpzXltUlkvmWMBI+2zdnn64oYa6yX0XTm0i4jQ3t6wmuV53xov5UPpyeeKyLbpFtZ6Xpmn6TqNq7/ic6pqQRR/DVf8Alq2fTOP0FXBnXU+ox32o3lzeW+JrxlMXHKR9wfbJ/tVWK5f3AnaAjafCTwwcY4BOM/qKKSjA4Dg8j37UHZKkE5P0olSFlcLDdJPbTNBOigjxOVZu3+80Rbbnrq9l0t9I6isRd2rgKpPlZMdyre9An07oupoh1zo2+lea2fMlr+WZFx7ZwwqWDVug/ihDq7R6b1EPwmpMNokPlVj8xng1BqEUe1EAJOMDOc5oDSxq6YYeuaAJF4oCBUQ7mJ45zQHYB14wR86AVjBXyjge1AEcRTHlA9hQE8kbgEohJ5yQM0ETHNqMOr3IZQ9tIMQyEjKt7D3FBLqywRPJKTuxlj3zQI3Ut14e+yhWRj28Q7RjH60EfpF3rU/jLqFrHbS4/hqpJXH19aCRa8jgiVr1xGwXzYyf99qA9tc29/aRXFnKs1vINyOO2KByoxwe9AYocHGKBvdwLcWzxSLuR1KuD6gjBoPHXWujt071Nf6YSSkUnkJ4yp5H7f2rQgWAA3Y+1An4j/1t+tBrHxKuYS+gx24LRx6ZFtI/lz60FY0+/v8ASphNpd68EpXY5AGNvzFF1YOirZbzVrvX9dkNxZWH8eeaY5Lyj8qj7kcVlETqOqXd/HrPUNzcNE16Tbwxf1JkEgD2AA/etBte9R2Oq2cv+p6XHJfBFjgmjkMaRgAAEqO5o1FWfbgjsR8+9AlI5CgEggeoNAq0iug8uD7g80KKmCcZ7fPmjJzJfT/hWtjJvhOPK/OOe49u9A96X1W90/VrRtNkkSfxQF8I5yScdvX6UGidSLpfVFzcvbRiy6kgZBGysFW7B9T7HHNSjU+o9S1iz0e2uNLmX8RYxJ+KgYeVwVGTn5d6gjug/iU3UOt/6TewQpP59skL5B29x/8AYoNHPB78Ggb2l3bXO78PKsoyVyvIBHBFAoSkbfyhn4GfWgTnmWFN7ybAvc4Jz9hQRdx1dp0S3Dw+JJHbDdPIUZUjX3yRz9Bmrgzbqb4x9Oxho4bB751O5HPkXPsc80wQHT/xrJ1IHUbGKO0kdRiBiAgz+YjnsPpTKN/tLy3vLOK5t5klt5F3LKhyCPemAYLuK5XMDEj1OCP71ArGWLMPT0oIbU7h11u2t49OllWWNm/FIRsjI4AI/egfQ2ktpbww2XgxoDl9wJ49cUCHUGv2GixM13Mkcm0squwUH5/SrgxDW/jFcXOteHb3otrKEEiRISRM3zGc49v1qDT+gfiBpvV7y2unxTxywRhz4ozuHbOR2+9Bmf8A6kNIEWpaZqiooEqtBIR6kHI/atfRjDEt3AKjgVQjug9j+lQWh72e/htTOzyeCnhHPomeMYoJvQum7vVD47K9jpsQBkvZ5NoAHcgUAa7rKamE0Lp9Xh0G1OZZTwZSO8jn9cCsivdS38F9cJDZIY7G2URxKe5x/MT7nNaEKrENwAFPPlosFwS2cd/cc0UlIm3JOeKDo2LH+UA0SjgDk98URzPiJ2449e/NAbS7v8PdpKkpikQ5WQLkqccGgmYNQmXWLeQLG9wVRQVPlcj+Yn3xQa98OviAjz3WjdXSpFdliEuJCNjDtsJ7enepRdel+kdL0rqOTVdIsoYklV1dixO3nunpg9jUCnU3WMeka5b2EUcl3JInmigQs6ZPlJAHY8+vpQP9O1m3nthNo0cTwM2JDwoVj6H5gd6CbhtUiVn8TcXO4ktkZ+We1BAf8Z6fZ2uqXWpyxQrbStGseQzMB2IA961B59+IHXmodXal+HsPFh04HbHCo25+bY/zQWv4f/CCxvII73qC8iuXYb1tYZeF9txHf6U3BatX+DvSl86x6cr2dwjbnEUmcj6Enj6U8hLdJdEX/SmowJp2tTT6Oc+La3HO0442+3NBf1LmRUjjQAfmc+nyHvWQockYyQcY3CgaabaPZxGNnaUFi3mPb6f+KA2q3RstNurnBxDE0mPfCk1YPMemaP1L8RtYN9fJPc2aMUaVmCKg54H0z6VRYendf6Z6T1W56a6j6fgfwJyguhGJmPzbIzjHtSjTn0zSunbi01fSkt9Os5GAmWNCDOGxtXb6HnNZEZ8etOF90DPKFy1rKk3zAzg/3rXI8u7zvOTg4zVoTLDJ81QWDTb2SwuvFgcrkbXwM5H0PFGqsjpd6+kcT61Nc2ieb8OikFc/9PA+WfSjKA1nWBzpFlZ/hLWM4KH8zsPVj6mghN4IyQRk5NGo5BkFmyAfSgVjChdpGO/FAXYpOHLBe/FAQqoBJbA9sUBGxgtgEj/eaCf6DGjt1TZf8RNGumKS7mQZQkDIB+WaMrf8Ub/ovV7V20JIYL62K4khhCLOCcEcAdu9BmCuEQvxvyFUg42+v+/rQaj0zax/EXRY9Nns0t9TtM+BqCKAjEclXA98jn+1Si7Cz6u6O0tLjTrxLu2tQJJrDwcKE/m2M2SfeoLrpupDV9Mh1OytUS2vIN8m4BZQf6T7+vPpj50GfdK9L6rJqk1y1y0elRDKRqdjHHoyDhjx39e9BZr7fagW0j3kul3iETRqHkeF8ZBUjkZIxjtk5rQ86dW6r+O1OcW0UtvaRsY4oWfLKBxz7k/5NA46P6X1rqS6WPS7V9v88rAqi/f3oN46X6C1DSotkus+BIwKl8hn2+3PapROXPT2t20bPY6kJ5UGYmbIfIHGW5z68VBI6DrzzWSrrAjtrwFUbDja5OBlfuaCbluJLeNwIpLiVF3bVXAP0Pv8qBxLO8cYcW7vnuqkAigNFKs8CyxlwG/lcYI+1A31ayF/pt1auSFmiaM/LIxVgwfoO413o3qqfSLyUSwodogAyZVGcbPTPr71aNDvendJ6wtbu7Fi1lezK0bS4VZMjtnFZE0bC5u9Jh0qRAr2yw4uWx59vBI44PegN1tpbap0lqOk2sipLPB4aFsnHbBNOR5A1exFhqFxbeKkngyMhdOxIPcVuhiZFz/zBUEwcKvYnP6fWi0+6chjn6h062uATFLcRrIMnzAsO9EehNR+GvTV3GUh0+O2YsGaWHIf9amjIfib0no3S0VtFY3M000zMzLJtLKvvkenyx96oz0rwNjA8cj2osFLbVAbOc9jRQiXOAwxnj3oBlAxwDj37UDY+vHOQeTQBIdqjcPMfnQwJclWyBgCjJBFeefw4VaVycBUGST2wAKD0L8H9C1rSIILjWLSCytY1lZASVnlL4PI/wD8+vvUo1uwbxI5GkjdVc7isvOBjtj2qBWKFZiQ8CJCB5FHYj5jHFArDbQ20ey3RY1HOAOPsKCH1u61CPSLt9MtlXUHUrbCbJBbPdtvYetXR5T1y2udD6lni1ErJdJLvlK4wWOCePvVgsV/8Sr67UW1vA0NiowIonMe4+7FeT9ARQRmodWa9EYpPBhs1Tygw26rk9xknkn70EjonxZ17TXjAeKTkZ3L+YZ7N8vpSjX+lOpNM6umgkMG3EgBV1DYbG4kewz2NZGkC43CP8MPFBONysMAD50DaHVH8S6N1a+BaxMUjd280pA5wPb296DrXWLK9WNoJdtwybxDKPDcAnHIoJBifTBzzmgaz2UFzPFNNbwvLCcxuyglT7igdRRKg8qAZ5JAAzQEnuYoHiSWQIZW2ID/ADH2H6UERr12BY6hueIQJaO7SK/nHfnHtx3pyPGWoN4jynuCfU963RF+DL/UtQWTkjaWY/8ATnHFGql+j1VerdJY8r+KiJz/ANwoy9C/EjqSbpbRY723RJC8ojIcZ4IJ/wAVkecer9en1+9FzeLCCq4URjgDP7mtLhteadBY2kMczyHUpcO0YxtiUjgH/q9celAiLy1kjCX1ruyMLNGdrj0+h+lE0+t+kNQltJ7yKS3jgiTxUFw/hySp7qp70NV6YEBgWUNjBoaKeAODnHrRoVgDnBP0ozpxZ2f4y5trVeGuJFiBPpk4zQep9C0LTembS30fQbWP8ZsDyTugZgf6ix9fYZpbgmbXSmXULaa6kMzpltzcjJ//AGpaLCY1CDsF74PrUCgHY0HbSx7Z96BGUfxB2xjtQZ11t0Tb6jNfyw2wM18gV5AcBdpzyPnV0Yp1F0o/TEczXjXaTOQYpIk3QlT3B9Rj0zVl0VKbVppImheUSwbsgFfXHc0De0tri/ujFYQSSyfmKopPHqaDV/g9p+padr/gkSRTzKu0kZRlPLYPbOPf2pg9GWzRCMJAFxH5do4wayKX1z/G0CdzqLWRkiaTxQBLudclQvovbv3oMU/4Z67uwnUAt3u1Zw42yhmx3/Ln8v0oN86L1d00i3i1UiGQIocNnEbnkqT2xgiguEbI4DIysp7EHNAZnxQQ/Usksej3EsCl5EUthR5sY52/Mjigr6Qrp3R15LqEcIlmgdpFGAsY2navPJApyPJtwd8rnGBuJz6Gt0MzGSTyf0qCwSKA5ZsAjnn2otTXQYj/AOMNIDqCrXUZwf8AuGDRG6fF6Gyfo6+ub0CR4EPgIScLIeAcfc1keatN0661a+S3sYTPKzAbV9B7/StLrQ/iXp9pYLp8elWsUM11AzXMqt53I7g7j244oiB6W6Tn6j2TeAy2FspTeB+Z+/8AmgtnWlvpdl1Dp1pq07Ja20GFQpuDHHAwPf39KDHriVTKSPOCeBnHHtQGsrG5v5pfwcTOIlMjgEeVfck0XRIreS7uUigRpJXOEVe5PtRE/wBJ9HaxqvUcdhNFJp0lviaSWVcMgzxgdySeBipo9T6O8NppUJ1K4iW5KgSvIyqxb5jPH0paJm1NvKivE6Mp7MpyP1FQLRTwy58F0cjuAckfagOTtO3+Y8igMWCIWbOPlzQNhNBOWEbq5Q+YKc4+tAD7JEZgQfXj0oI/VtIttXsZLW5hRopByCP/ADVlGRa78Erae63aXK1tG3LAncM/Kmh10l8IZdBv4rxtTE0yggJsyoz6/P0po0zSNKEMdo9xGnjxuzkqMAEgjj7GmialjWQMgyCRyQcGoITqHT7q/a30+G2jFmwLSzl8GPBGFA9c5NBPRwJDbpHCipEi4CjtigqfWltqCaG8WhNbxyzOBIs8W8FcY4+dWQQ/wtuZdIGqadrknhy2u2QyOSEZOeRngY+XvTBZZevOmhC8janbqiZ53Zzj2FMFcs+sh1ZqsFrp8UkGkrlpbh+DNzhVX5Z5NQTfXyWUXSV2t+wW3EZ5I4HHt61eYPI0mA5C9snFaoLsPv8AvUEk5JcA8cZG480WnOlXX4PVLO4yQ0cyP244Yf8AiiPUfUump1B0/c2O8xfi4v8AmL3UcGpgw/SujNX0Trj8PpckimOMvHO/kEg9Rjs3PpV0aFq/Qqa1ZJ/qcrverEqNOwGM+uMfemiVtrKbQdMNjp9rvtkhPht6mU5yT8u1BkvXg1qXUtOvddgRY1R3j2YHiMvZSD27CgzSCyuNQ1KK0giL3Mz4VAOc/wDignoNNOnaHeiW8hgkku/Al2+Ziqgn09M0ETp0qpqSmGKOdFcEeLwMfPHag3JLuCRtPmQWsDhNphtVAcn1w3BPFSwDdWGpX1/OYdOtbbSrlQ80szHdn0GR24/c1AbWemdatLbTJdGvJIJypDQwMV3exwOPatSz9Ei/R+txy2mr3evyHV4miWIDhGwwyGA7nGRS2YNZAUBWYDdjGayEvxMYB3nYu4KCfU+woG93c2enWs1xcPFDCp8zEgDPzq4GGgz22saS1zZSZhkdsFePXt86YHWmySeLNDMYikZ4YNlvvUD+VARxQJqgwRQHUAAe2O1AWOFRM8mDlgB37fagb6reXFt4ItLZJnZsuWfaI0Hdjwcn2FAz0nWX1i4u4xY3VpFbv4eZ1x4vGdy/KgkriN2aMRlQoOW3DOR/5qwYr1P1tp2pdS3WnanKkGh24kRl2eaYgcb/AFxnnAqiv9Jno0dRLJPbtdQtkNPIALaMnODsPPpSjbdK0DTbWQXui+Gsco3BU5hPP5gPT7VkU74t6PZHpq/1N5ZZbwrtRnmOwDPOFJwPsK1xR5ybudw788VaC5X2WoJRULSBpAe5PA/aiinAZnHck4A70THq/Qr23/4Y0u4lmCpLBGA7epxjH60Du+WGOBvFlFuWOFcYyCfbPrUojri6k06xX8PFNfBUJ3ltzM3scVBjfVvVXVNit5dapNDZGQGK3shjeAe7YHIwAOT3zVggNTiu+orrR4p7m+upJFR7h3TPhggDaoBwRjnPH5hV0af0xotnoD3l5dWdrY2YjGLhwPEHoef996CC6m0HpuPpk3Wny2s9sJPHJ3AeI2D39T37UGU9QTDULuGPSLPwIyoVIYk2lj6/X70G2/DPp0hVudRuBLcwxhRGkeEjB9M+p96DSLprVHiieaAE+YxHkke4H1qUOIBawL4uAuc8nvj71AwjRtQ1eO78QNp9odyLju/qT8uf70Gb6r8SpLzryy0vp+4NxYSSCEswI2u2Rn3OOD9qC4dVamen9NlaC7tUaIFvCmnHiy4HJXJxnOeDVwed+rOvLnqSyWO4jZSru/kc7ck+30GKosXw2+KmqaDJDY3jR3OmqNoRhtZAP6SP7Ggtmt63qbTJ1XLazJpslwBFblypEOAA7L2OWANS+xrnR2vW3UmjJeWp8wJSRf6WHeoJdSPMCRmgMq8DmgBpNsgUIxBGSccD70DczmS8MDWoe28MN4+f588rj980CktuJZYpFdlKZ4B4OfegQ1hpIrVjbsRMBhBj8x9qsHnX/hm36y1O/u9V1ddPmS6aD8OkQdyxOSe4OMmqLUvwQsYY4Xjv7m4YEEhwFyMY7fXB5pRbvhp0jqfSMV7b6jqZvLGQAwxAEBDk54PuD6VkVb49a5DBpiaNaeF/FIaQDumOwpzMGDEZQZ5+VboR8In1I+9QWDY6gFn7jjHpQhtJEFbAGBnijT0P8H7qPVOh47a42yNaymPBOcDupoykep+m73V7g/8Av2itQowvJIx6j5/OpRjfUWrax051RPY6LqFy8YACkebO4Z7HjNWCY0ToW2utJbqPreW5na4O4R78cehY9+fQVKLX05p1ro97awC4kX8VFmJLeEKdoyfOxJPbHbHYVAz0rqKPWNauri9t1ktJgILYgEiNFJ/Op9STmrBBdeaFCo0y3jt444DI3jLE204Y5DD+9UPPhv0NaRtPq99mSLOy22nOfdh75oNC0vT7m1uJGvGiii3AW8UDbQAeDu9zUohLlhouqap1VciF4I1FtbxSthtobBIPuTn7VBJ2vUth1TYk2ULi9iALwyKQYz6Z9CM0Ft060/DWEcDHe2Mucdye9BFW3SekWt3LPb2cUTsd2UGCG9x7VYMzufhzdX/WmoXj+BPpx3I7XZMmXYckc8EVRKaP8I+nXikLQuxOQSTnBzj6UEjonw90XSrq3S3s7dplJcl1EhGDx396lFx1TQ4NVjaC7UNCU2lAO/8AvNWDCLp9X+E/WgWImXSp2LRq7eSRT3B9iP8AFSjd9P1+21TRodVsMS2rLmTbyUGOePXFQSltcLcW0c1vh4mXcjDswoDLdRm4FvISsgXeTghDzjAPbPyzmgVFxCzuiOC0WN3sM+5oDqySJmNg3rx7UFb60tNUubGJdFdEvhIdryflUFSM49TVgyTQenJemOorf/U4H1Fpp1edAh/hOQTuQ9375JA4q0bnbPBcxxT20wkjKkqYzlT9ayGWu38um2MbLEJ7iRtoUds+/wAgBzQeW/iHqi6j1PdzeL44HkL9txHtWhVUOVyvHNB2F9zQT8hUAhAdp5FCG0mSAzE4HGDRppvwL1bwOpJbEsFiuYyVX3deR98Zoy2ZtRgmjkSRZocEp51K7se3vUow/rfpFE124mVpfD4mk2MWdCc4A+VWCH1281/UmFnpklzPYRFBEG8uGC4yQfcn9alGgaJo95rRsbi53WaxwrHOm7BjYcHnvz/moJaw07pXSI5IW1K0CQnDhpAWB9R796CudY62msTRW+gadI8KnDXMkLLv9MA8HGOKC3dAXF1dRfh75f41moi4G0AdwcfTj7UFhv7RjqMBV5AJFZHkR8FRjIx6CgpXVNjJ1JqNn07p26CztSJLlpIydyj2J+fGaC+afplrazqLa3SKNIggx3IHYUEsBk4wQc4oK11L1z070/M9rql6wuVA3QopLcjNBDwfFboqeSO2W7kQNxuaEhQfnQLt8TuireVoV1UeXnckTFT9DigHRuv+mbu9ZV1W3Nyc4IRlVl9O47/KgtU+s6baw+JcX1umRkAuM/p3oK/1t0rYdX6cqXKESqN8Ug/Mp9P1qwZ702mo9GdUTWJsmOn3EY8CAORGXJAwScjJ5q0bJDNLb6YklxbKsgA3wwndg9sDtWQN3aw3ZKTwLLEQOGORn6ehoG1vYAw3FikRt7JSuH3Hc/GSc5P0oHn4aO2uGuYyiose044wBQIm6F1dwfh5ARs8R8L2BHGfnQHv9PS4PjxrGLtFKxysm4qD3oCxboIIo7e1jhQHzAYUJ8wP8VYM56j1ktaal1BMrS2sAaK1OQDD6eUepY9yfQVR5zv7hrmaSaRtzyHJY0DcE4BPIPb5UBwOO4oJYzFvzEYHAH9XvQhNZN7AEgDOSDRo/wBA1SXRdVtNQgb/AJUgfBHcZ/8AGaGPVlhPbarZ2t5CEeORBKje2RUrI1zYxTBhMinIwcjvUEcugWkO4AMisMEA8N69u3yoERrOhWNxNYy6hapcxAeJHM+D8u9ASLStLlm/EWdpZyxy+Z3RQ3I5B44oJKTT4blFWSNBEOeBg5+goFYbOK1TKhIxnIbGMH50Cpcyo6AMrIcM2OD68Ggb6Lbbllu5Cd88hYBu6rztWglSNkfm4P70Gaat8Rba96w0vp3R2mhufxyi4kO3YyDOV9+f8VYMw+P0cP8Ax4JVuEKzW8bEr5tuMj0+lUZ7Y2X4288GK+towRlZXYqv9uKCQi6YmbT2u11GzaJWKnYxbBB49KCFnhubdiwL+U8OhP60ElpXUFxY6nDdXQF0qYbZKxwT9vWg3npb42aHcmC11C3uLSQjEkpIdQfr3xUondP6x6e6tv7e101hczRzrNtaFiFC/wAxPYHtUF+lj8bYCTgMG59cUC4OBQQOo2eoXepFTeL/AKYQN1sEwWx6Fu+DQLX2kw3Ok3Vjas9qJ48Exd1PHb9KCE6R0G86Ut7mK71KK4gklM7TyKRIBjtjtjj96AOreudJsrMJbXksk8jBCbVdzRjONxBHP/3QQ9x1jcWGkERWWqXdpMPCt7x4wfFOOWPbA+fAqwZr8TJ9Qbp2ymvEjsrSTEVvawyHz45Lv6E4wPqaoyl8g91OKDlYEc8mgKW5PH7UE80f8PPHl7gDFAZkUjawUIQG8w5ouknAUbl9Dg59KK1X4Z9XXFvo8mlRXax3KHfBG8Rk3qe6jHOc54+dMZO7jr/qK8vWtba4tYu38TwvDOMc8N60wPLbrW10PS7pnvrnUtbAKobgBUUk9jg8f/lMC2rydMdRSaRqWoLEbx4UefwxkL2BVvvn9Klgv3Tp0lPxFno6wJ4IVmEOMEHsf2xUD2e4ks7n+NGDaCMu8q8lCMcEfPNA6tW/EwrMybEYZUHnI9Cf/FAzu7G4LXTWs38SRNqhs4Bz3z9KCO6x07UNT6altNMvEs7xkC7nPlI9R2/egwbrDT+r+kupLCeK9nu3KBYGRy+QvdWFWCU6avtA6h1iKDqLRhpmpvkxz2p8JGb3z7k557VRX77TdHteuPBut401CAouyXGcdvmASaC069030brYaay/CwPFwWspRErfUN7UGZX2hWSiY6ZrMc0CvhUlBUk/UcGgiLq2mtG8F54yDwfDfIoGkrRsSZXwOB2zmgsvw06XHVfUcFvI22xQ753Ze4H8v3OBUo9a6XodjpltHbabDHZIhVsQqBuA9DxznFQTQUe5oDYGMnn7UEbpV3JqDyz+BJFbBtsXiDBf/qx6CgDXL42cSRwGM3UzBQrHGFzy32oG2i2kKTSI80lzMow0rqQoyew+3tQO59KtJJRI9rEzgg7igz3z/egZ6paJdGGwW4eBXy7pGeXUdwT6A5qwebPjJrcOr9TvbWZQ2Onr+Gi2nIJHcj7+vyqigOuRk+vtxQAqEk4BU0ABj7j96CzzKxYD0GeM0CQG3OMAjkfOgbSZwzE4PJyfWi6caTdzaffW95akrPFIrLg/tRHpGzs9C6t0W31FrO3Y43MrcbH9c/eloZ6v0JpWoKlrHHBbScSFEHYc5Pz71NDXUoJrK1g0dvw9qsspW3nXaN6KMrHnH5ieSfan0U3Rr1uidaRbiwk8BUSS6naQkjc3ZcHaRnn70wbja6lZX+nw3NvMksM+FXnPJ9DUCeoXj2hSG2t2km7op4U/f/FAvHaNePb3N0jRzRA7VD8Akc9u/FAvcxnawZQ3HYtjJoKfDFAdeub6Vo1dSULIBtTbgYOfU8jNWUVvrm5ih0m1urixhlsI5HJliOwR5/LkkHHJPamjHdQ0HWdemlutN0+YWBYtC0rHDhjwVz3zWgx1n4e9U6QE8XT5Zd//APR5se9XBXbjS9S0zAvbO5tyWKAOhG4/KpQ3ZHXO5JFK98qRUGhfCbph77Uvx91pv463wVjR0LR7s483796WjW7rTrXpHWrSW2YK7lmXTbaIFpCRjjHOOSeeBipaNLtXuIre3R43lnkGXYADZnnmoH6Dkbzn6UDGWe9a/hKG3jsW8riQMJS3svp86B6zgMQmDtGT8qDNb6XUpOoPx72tzOkjFYowOduDwDjj70Gg6Wsq2KNeAJKRuKk52fIn5DvVkENrvW+iaSAsl0txI2Asdud5Yk4A4pgzv4l9ST6JZSXbyyprWpw+FFa5G21gz5icfzH3pgwCSQlh688+tUEwjjngZ7UHAHuWAHpn+1AXj5frQWXOGBZcKSe3c/rQIyAtnI27eBj/ADQIMAuH8vHBB9DQwVpPLjOckEZ/ahi9/Czqj/S9VhtLm6aG1uZFUsT5VOfX5Gpg9GiNJArxsrxsv1BHypYGF7pljeG3kvLZSlqzNGGxhSRjP6GoG1yLUWiWc2nSPA4KJGItyYHYHHarop3wu0jWYNUvzriNBp8ErraRMANxJ/N7nA7ZqDUHgSQLvAbacjI7H3oOuIFuYzGS68jJRyp4+lA0m0yDwGjiTw3bzBwTuDe+TQVbV+mLmW1NtbSok9weZiC2zPLEZ+/FBM6Xo40/TYdL8Jr21G4vJcuCck55HbFWUKQ/h4tR/DTz2o8TK21qmMgKOf8AfpmrokljG1i5BHI57D5VNorut9Lab1LA638W6H8sboNrqQckq3pntV0RWsfD6K7SGC3vTFahQJY2iVmkI9d+Mimie0Hp2DQ7AQacio3JZgqjcT3zxk1KHGldPWtnqMupS5uNTmGGnk5KjGNqf0r8qgmkhVGcquGblm96BDUZZYLGVrdN8+MIvux7UGKTdXdbaRrFvbaxbWN4d58BmwCjHPORycLx2q4LNe9S9TdN6I13qkWmzSXdwBCGlO4hiMKAB2A9ag0WySQwpLLtMjDcQBhVz6CgoHxF17XbnUYunulgsUsu4TTvjIUAEhR+x4qwZwtkOi7651PXJobm4tohHbQhdgecjnaPZeOfeqMy1vWLvWNQlvb+ZpJpWyT2A9gB6Cgjy5AO4A5oAGRgBR39aA7Z8MkFtxPY0AbV9UGfpQWhj5TkBQGxuBoEGG1iQCyHvj1oELgSkK6oRnIBIxzRdJ28Q3+fHiAds96LoH3AF1wCfyijNbF8JviI1rbQ6Pq/iSopxFOx5Uf0n3qUbWQk8II2SRyDPuCDUHMpSIiJQSBwDwKAgTxApnEbyIQ+APyn0+9A5B3AgfmoEWgcb3VlMpGFYjt+negSs7zxH/C3RWO9UElM8SAHG5fl/agNdXcEbJAZ1WadvDQDJO7Gf7c0ED1dqWv2enzw6Rb24nZfJd3EwREHqxyMZHzOKBbT7H8PZWTK5uZ9o3Xm1SzEry5PsT7UFF+JnUezSZ9LttRs2km2m5KSFWXDZI491AyBzVwK6J8T7CRtPjee0tbaGAtdNISdoXgLEo5JJxyfSmC6aF1fo2vELZXDJOxwkMybHYe4HtUFiJWJd8rKqjuTQcZV8SNI0dy43BlGVA+ZoBniE0RU7tp77Tg5zQUv4hNrU2tdNWOhylPEnaS5UHGYlAzn5cn74oHGt6l0z07k6nJC123HhKPFlbPptGTj9q0Kx0XMvU+ty6vqQtpWlZo4LOdGDWsak8Aflycgk+v2qC8a1q8OnaXLPOz2kCIWkZ+CqjgYx6n0xTBkmp9Sabp0KdRyI5vJkaGw08MVKIDw8jA557896QY1q2o3eqXr3N7O8skjnlnzgn5e1UMCGV/MOM0BJFOVwfX0oFtgZTjkg8UBtpOeO1B3hg85FBZXVMM+VJAA2+h96BO4IMJ/p7qvuKBKacmOKB5CYYx5UzgDPfHzoGwD5OApJHAHrQEAk8NWdNpx+XdkA0AIGhkGWOQcgg8UGw/DP4kmwhi07WCTZqAiSbstGc4+pFKNvs5o7q2Sa3kWaJxkOp4NZDOHUh/qL2k8LW78eG7kbZv+0+/yoEZp7fUpX/BXpgvYZTCSRtO7vtwe/vQdY6jeyatPp91FEPw8aSNMoYbi2cADt6Z70DS60KW7luJdV1JniJzBtURG2b0KN7+/vQKSWUWnLLqN3cSLP4ex5Y8jxiPykr23+nzzigpXUPVOu6Vqmmf8UWttb9OXDqkjRnfI3H849uRkDOKC0axLFr+nLB0rrUMM0bqCIGGGX1AH09qsGc9UfBiTV9Vhu9Pu5oPGLNeG6bczN7jHvVEr058Gre3sLeDVrmOdo3LmSFNjEH+XdntQXO51XQOl5YrCKGWa8SMYS3tzMyLjjJHb9alDqz1S5ktJ7nVdLmSVDiOONfEMiE4Xy+h9xUDm11CaTxEOn3VmpHFxKFCr9s5GPmKAus6jb9M6RJf3c88yxpjcxL7uM5OO3HrQVTSupoOuYdZMTSpptriNFtXKXDA/Pjhs9h2xQOJ7Xpnpa2S91WK2swqjbGw3ysfcnuxrQsGmapYvpwvra1FtDL52Mi+Gx49sZoMb+LXV0t+jWl3OYLGTO2zjx4h2nyszHsG4/Sgxt5ZJmEsjl3PB3GgSlyXBxkDnNADseB2PsaA8SoXQyFgmQCV70B5R/EIjYmPJxnvigEKcYDfrQF2/X9aCwqC7l2zwfT/FAJJ5747E5oGTqZArKOfccftQHZWwmOD23Z4NAEkTEBmwR7g5AoG7KSSE5HyFAMTyQsMHa/cEcEc5oL58P+v7rppdryPNAXx+GfsQe7Z9D2/Wg3zSdX0fqzT08F433eYwscOpHt9PcVkQPW632mX9vfWdrbXiRgrIdu2eHIwGD57+nIoKdc/ELVdC0u5afp27SUtta5vJMMzk+UDjzYHtQWDpj4gxXmif/wAitXZkGZzFGW8MehZO+PmM0Fibr/poWQmF6xXA2xmFg59sKRk0C2nQP1KFvdb0vwIUJNtDKcsVP8zD0Jx2oJDTNA0vR5p7qzs44pJOXkUc/SgNfa/pNvbF5L2JgTsCo2WJzjGKA1jcNcxOF/m/I0zbt4+gxgenNA5s7CCxWWYQxpNLgyMiY3nt2oHajcuexAoEL1C1uyFkVHO1ixHb17/KgwT4rdXWep6oul2OpywaTYqVLxDyySDjaM9x6Z+tWDPdB1TW7Wa9sumpGlursqMQRlpXwd3BA4571RcdN0i41G7h/wBSmNxqdkwn1O6u5/4cAXlYgcnngE/pQNvih8S211obHRyYbWInfJG/Ex9MD2+tBmNzcTXTtJcSSSSHH5jngDAH0oEdxbg5A9wKAzPwO+fegSLfLJoFoR5fUfegXOcHGAT8qAM+XaBzQCCwGDuyPlQWJpV37Q5TIweM7u/f9qA9vNYpFML2KaR8YiaJgAh55PvQRvnYoqA+MThcDnPai4PKWQlH3K6tggjnPaiEmz4ZznBPfFAVWG0AZDH1z2HzoE7lhv8AJIHI/mGRQI8AEeuOMGgndN6pu7V4RJLKY4WDLhypXj0oNL6d+MMS4ttetDdQgDNwAPEwPRh2NZGkabrvTXVZiexvba5aI+ILWZQG3Y4IDdvtQScvTdjK8chtFjkQ+VlYgqPXGKA17daV07apJrV9CsZbELTgbu3YY78UEHf9evJ4K9P6JqGoiR1XxjCUjAJ5OT3NBM9YdSWPTenwy3t7bWbSuBunUthfUhRyT+1BA2vXnS/jGdeo9LnIHljeLwSCe5zgmgejrOz1S3kGhazoaXYGAJ5Sw3e38uaCsJfX02rPD1XfXtvcCXdBJGjLbOO+EK88Y7nIoLB1H1Bb6WkN1ddSQ29io/5MZEjzt7DGTjj2FXNGUfEH4wRaxCtnp2kwGGM7llvBvIOO4XOAe/fNMwZbqusalfLBHfzSvFH+SIgKo+igYqiwWfWV30rpp03p6exJnUPJexQnxuR+Ulu2PkKCrT6jcSiTxZnbxCWcFidxPJJ96BBDlQ35fbFAbahBHJIGO+KAIwg5YnB455oDkKcbW7UAOowSMjOORQcCVXPp+9AqDkHcDmgMNpHPcUBTuzQWCJXcFvKR2Y0CMiqjnz4UcH/6oG8gKluwxyAfSjQ6ylEJBJfv37/OiYQMjbjkZXOSP/FEELAEkNn1waBCXdjORnPoc80CZeTb5wQe2BQAm4y7jlhjvQcWO3cW4GB7ZpgGC5a3uUeNyGQ5GCR+45pgt+l/EzqLTgxj1O5Zc4CSOXCj70wOE+Jd/Pq0V7qVvb3bISAWUBhnuc+/2pgvkHx0soLaNIdKkEiqR5yDg47cYpgresfELSNc1n8VrFtAw2ZBiiywwcgeb14x2xTBYNA13ozUo/GOqWVizDc1nf6crIh/7wOf1rOURvVupdE6ncpFeakiSWsZdbjSLfw1Zs+VVyMHA75xWsFDHU0idTJdf65rT28YKpPvHjKp9Bk49qYK/rGpXF/qU9zPdyzyyMSJJAAx9ifnVlwNZ7vxYEh8GAEHO8DDH5H5U0IPK8jHxSzFQAMnOKgJkFwPT6UBlAII5z3zQCjnA5OKBXeuAT9KABMA208DtxQHRhzgUC3KjJx9z2oAP6/L3NAHC8Hg/XNAcNtGe4oEy5yeaCdLk7yx2qQCAO1AmXZSSexHbPNAhJuLJkgjvzRonuAJy2cd8UCbyOi453Dj7GiYTZyVPPl74oYLJIyq68EH3Gf3oYTDEjLbiP1FEDHOUOdgOfXIBFAm77j5Mnng/WgLI5UE8Eg9iO9AnuJbuQx5wOBQFRxuIbOc54PrQK28ws76F722EyI4d4HJUOPb35yKBm8oeQsi4BPbPb71RyYIHmPGRg00GRsbsHIPY0Bg52AEEseBUCQJyOPXtQDtcdvvjtQCQ/GBwKAuXU4PrQBvZE5IGeO1AffjBJ57UBvEO045HagFWAAzktQKIzBeMg0C5kz5mOG/WgMrDJJ7jmgEnIyOccYoA3cEMRj05oC7/wDeBQTduzEoNxwcZGaAJOWfPNAlISVOT60aIQfkj+amgJ3bnnigKeFGPQUCf/x0Smw4V8exogX/AOY3+/SgKxKxeU459KAgJOckntQJkkcgkGgAAFFz/XQEmJaY7jnk96BM9yPQelAf/wCX7UBv/jagGP8AKB6ZoDf00HMfO/0oAH5TQA/5moECSMDPFAvGASMjPP8AigVX+b60BW7/AHoHEJJD55oDd4snv70CsSjCcDmgVAAbgYoGYJ3nk9qBUAYHAoP/2Q==</binary></FictionBook> \ No newline at end of file
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info><book-title>Pandoc Test Suite</book-title><author><first-name>John</first-name><last-name>MacFarlane</last-name></author><author><nickname>Anonymous</nickname></author><date>July 17, 2006</date></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p>Pandoc Test Suite</p></title><annotation><p>John MacFarlane</p><p>Anonymous</p><p>July 17, 2006</p></annotation><section><p>This is a set of tests for pandoc. Most of them are adapted from John Gruber’s markdown test suite.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Headers</p></title><section><title><p>Level 2 with an embedded link &lt;/url&gt;</p></title><section><title><p>Level 3 with emphasis</p></title><section><title><p>Level 4</p></title><section><title><p>Level 5</p></title></section></section></section></section></section><section><title><p>Level 1</p></title><section><title><p>Level 2 with emphasis</p></title><section><title><p>Level 3</p></title><p>with no blank line</p></section></section><section><title><p>Level 2</p></title><p>with no blank line</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Paragraphs</p></title><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<empty-line />here.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Block Quotes</p></title><p>E-mail style:</p><cite><p>This is a block quote. It is pretty short.</p></cite><cite><p>Code in a block quote:</p><empty-line /><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><empty-line /><p>A list:</p><p> 1. item one</p><p> 2. item two</p><p>Nested block quotes:</p><cite><p>nested</p></cite><cite><p>nested</p></cite></cite><p>This should not be a block quote: 2 &gt; 1.</p><p>And a following paragraph.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Code Blocks</p></title><p>Code:</p><empty-line /><p><code>---- (should be four hyphens)</code></p><p><code></code></p><p><code>sub status {</code></p><p><code> print &quot;working&quot;;</code></p><p><code>}</code></p><p><code></code></p><p><code>this code block is indented by one tab</code></p><empty-line /><p>And:</p><empty-line /><p><code> this code block is indented by two tabs</code></p><p><code></code></p><p><code>These should not be escaped: \$ \\ \&gt; \[ \{</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Lists</p></title><section><title><p>Unordered</p></title><p>Asterisks tight:</p><p>• asterisk 1</p><p>• asterisk 2</p><p>• asterisk 3</p><p>Asterisks loose:</p><p>• asterisk 1<empty-line /></p><p>• asterisk 2<empty-line /></p><p>• asterisk 3<empty-line /></p><p>Pluses tight:</p><p>• Plus 1</p><p>• Plus 2</p><p>• Plus 3</p><p>Pluses loose:</p><p>• Plus 1<empty-line /></p><p>• Plus 2<empty-line /></p><p>• Plus 3<empty-line /></p><p>Minuses tight:</p><p>• Minus 1</p><p>• Minus 2</p><p>• Minus 3</p><p>Minuses loose:</p><p>• Minus 1<empty-line /></p><p>• Minus 2<empty-line /></p><p>• Minus 3<empty-line /></p></section><section><title><p>Ordered</p></title><p>Tight:</p><p> 1. First</p><p> 2. Second</p><p> 3. Third</p><p>and:</p><p> 1. One</p><p> 2. Two</p><p> 3. Three</p><p>Loose using tabs:</p><p> 1. First<empty-line /></p><p> 2. Second<empty-line /></p><p> 3. Third<empty-line /></p><p>and using spaces:</p><p> 1. One<empty-line /></p><p> 2. Two<empty-line /></p><p> 3. Three<empty-line /></p><p>Multiple paragraphs:</p><p> 1. Item 1, graf one.<empty-line />Item 1. graf two. The quick brown fox jumped over the lazy dog’s back.<empty-line /></p><p> 2. Item 2.<empty-line /></p><p> 3. Item 3.<empty-line /></p></section><section><title><p>Nested</p></title><p>• Tab<p>◦ Tab<p>* Tab</p></p></p><p>Here’s another:</p><p> 1. First</p><p> 2. Second:<p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third</p><p>Same thing but with paragraphs:</p><p> 1. First<empty-line /></p><p> 2. Second:<empty-line /><p>   • Fee</p><p>   • Fie</p><p>   • Foe</p></p><p> 3. Third<empty-line /></p></section><section><title><p>Tabs and spaces</p></title><p>• this is a list item indented with tabs<empty-line /></p><p>• this is a list item indented with spaces<empty-line /><p>◦ this is an example list item indented with tabs<empty-line /></p><p>◦ this is an example list item indented with spaces<empty-line /></p></p></section><section><title><p>Fancy list markers</p></title><p> (2) begins with 2</p><p> (3) and now 3<empty-line />with a continuation<empty-line /><p> (3) iv. sublist with roman numerals, starting with 4</p><p> (3) v. more items<p> (3) v. (A) a subsublist</p><p> (3) v. (B) a subsublist</p></p></p><p>Nesting:</p><p> A. Upper Alpha<p> A. I. Upper Roman.<p> A. I. (6) Decimal start with 6<p> A. I. (6) c) Lower alpha with paren</p></p></p></p><p>Autonumbering:</p><p> 1. Autonumber.</p><p> 2. More.<p> 2. 1. Nested.</p></p><p>Should not be a list item:</p><p>M.A. 2007</p><p>B. Williams</p><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Definition Lists</p></title><p>Tight using spaces:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Tight using tabs:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /></p><p><strong>banana</strong></p><p>    yellow fruit<empty-line /></p><p>Multiple blocks with italics:</p><p><strong><emphasis>apple</emphasis></strong></p><p>    red fruit<empty-line />    contains seeds, crisp, pleasant to taste<empty-line /></p><p><strong><emphasis>orange</emphasis></strong></p><p>    orange fruit<empty-line /><empty-line /><p><code>    { orange code block }</code></p><empty-line /><cite><p>    orange block quote</p></cite></p><p>Multiple definitions, tight:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Multiple definitions, loose:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line />    bank<empty-line /></p><p>Blank line after term, indented marker, alternate markers:</p><p><strong>apple</strong></p><p>    red fruit<empty-line />    computer<empty-line /></p><p><strong>orange</strong></p><p>    orange fruit<empty-line /><p> 1. sublist</p><p> 2. sublist</p></p></section><section><title><p>HTML Blocks</p></title><p>Simple block on one line:</p>foo<p>And nested without indentation:</p><p>foo</p>bar<p>Interpreted markdown in a table:</p><empty-line /><p><code>&lt;table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />This is <emphasis>emphasized</emphasis><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;td&gt;</code></p><empty-line />And this is <strong>strong</strong><empty-line /><p><code>&lt;/td&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/tr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;/table&gt;</code></p><empty-line /><empty-line /><p><code>&lt;script type=&quot;text/javascript&quot;&gt;document.write(&#39;This *should not* be interpreted as markdown&#39;);&lt;/script&gt;</code></p><empty-line /><p>Here’s a simple block:</p><p>foo</p><p>This should be a code block, though:</p><empty-line /><p><code>&lt;div&gt;</code></p><p><code> foo</code></p><p><code>&lt;/div&gt;</code></p><empty-line /><p>As should this:</p><empty-line /><p><code>&lt;div&gt;foo&lt;/div&gt;</code></p><empty-line /><p>Now, nested:</p>foo<p>This should just be an HTML comment:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Multiline:</p><empty-line /><p><code>&lt;!--</code></p><p><code>Blah</code></p><p><code>Blah</code></p><p><code>--&gt;</code></p><empty-line /><empty-line /><p><code>&lt;!--</code></p><p><code> This is another comment.</code></p><p><code>--&gt;</code></p><empty-line /><p>Code block:</p><empty-line /><p><code>&lt;!-- Comment --&gt;</code></p><empty-line /><p>Just plain comment, with trailing spaces on the line:</p><empty-line /><p><code>&lt;!-- foo --&gt;</code></p><empty-line /><p>Code:</p><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><p>Hr’s:</p><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</code></p><empty-line /><empty-line /><p><code>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Inline Markup</p></title><p>This is <emphasis>emphasized</emphasis>, and so <emphasis>is this</emphasis>.</p><p>This is <strong>strong</strong>, and so <strong>is this</strong>.</p><p>An <emphasis>emphasized link<a l:href="#l1" type="note"><sup>[1]</sup></a></emphasis>.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p><strong><emphasis>This is strong and em.</emphasis></strong></p><p>So is <strong><emphasis>this</emphasis></strong> word.</p><p>This is code: <code>&gt;</code>, <code>$</code>, <code>\</code>, <code>\$</code>, <code>&lt;html&gt;</code>.</p><p><strikethrough>This is <emphasis>strikeout</emphasis>.</strikethrough></p><p>Superscripts: a<sup>bc</sup>d a<sup><emphasis>hello</emphasis></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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Smart quotes, ellipses, dashes</p></title><p>“Hello,” said the spider. “‘Shelob’ is my name.”</p><p>‘A’, ‘B’, and ‘C’ are letters.</p><p>‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’</p><p>‘He said, “I want to go.”’ Were you alive in the 70’s?</p><p>Here is some quoted ‘<code>code</code>’ and a “quoted link<a l:href="#l2" type="note"><sup>[2]</sup></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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>LaTeX</p></title><p>• </p><p>• <code>2+2=4</code></p><p>• <code>x \in y</code></p><p>• <code>\alpha \wedge \omega</code></p><p>• <code>223</code></p><p>• <code>p</code>-Tree</p><p>• Here’s some display math: <code>\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</code></p><p>• Here’s one that has a line break in it: <code>\alpha + \omega \times x^2</code>.</p><p>These shouldn’t be math:</p><p>• To get the famous equation, write <code>$e = mc^2$</code>.</p><p>• $22,000 is a <emphasis>lot</emphasis> of money. So is $34,000. (It worked if “lot” is emphasized.)</p><p>• Shoes ($20) and socks ($5).</p><p>• Escaped <code>$</code>: $73 <emphasis>this should be emphasized</emphasis> 23$.</p><p>Here’s a LaTeX table:</p><empty-line /><p><code>\begin{tabular}{|l|l|}\hline</code></p><p><code>Animal &amp; Number \\ \hline</code></p><p><code>Dog &amp; 2 \\</code></p><p><code>Cat &amp; 1 \\ \hline</code></p><p><code>\end{tabular}</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Special Characters</p></title><p>Here is some unicode:</p><p>• I hat: Î</p><p>• o umlaut: ö</p><p>• section: §</p><p>• set membership: ∈</p><p>• copyright: ©</p><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><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Links</p></title><section><title><p>Explicit</p></title><p>Just a URL<a l:href="#l3" type="note"><sup>[3]</sup></a>.</p><p>URL and title<a l:href="#l4" type="note"><sup>[4]</sup></a>.</p><p>URL and title<a l:href="#l5" type="note"><sup>[5]</sup></a>.</p><p>URL and title<a l:href="#l6" type="note"><sup>[6]</sup></a>.</p><p>URL and title<a l:href="#l7" type="note"><sup>[7]</sup></a></p><p>URL and title<a l:href="#l8" type="note"><sup>[8]</sup></a></p><p>with_underscore<a l:href="#l9" type="note"><sup>[9]</sup></a></p><p>Email link<a l:href="#l10" type="note"><sup>[10]</sup></a></p><p>Empty<a l:href="#l11" type="note"><sup>[11]</sup></a>.</p></section><section><title><p>Reference</p></title><p>Foo bar<a l:href="#l12" type="note"><sup>[12]</sup></a>.</p><p>Foo bar<a l:href="#l13" type="note"><sup>[13]</sup></a>.</p><p>Foo bar<a l:href="#l14" type="note"><sup>[14]</sup></a>.</p><p>With embedded [brackets]<a l:href="#l15" type="note"><sup>[15]</sup></a>.</p><p>b<a l:href="#l16" type="note"><sup>[16]</sup></a> by itself should be a link.</p><p>Indented once<a l:href="#l17" type="note"><sup>[17]</sup></a>.</p><p>Indented twice<a l:href="#l18" type="note"><sup>[18]</sup></a>.</p><p>Indented thrice<a l:href="#l19" type="note"><sup>[19]</sup></a>.</p><p>This should [not][] be a link.</p><empty-line /><p><code>[not]: /url</code></p><empty-line /><p>Foo bar<a l:href="#l20" type="note"><sup>[20]</sup></a>.</p><p>Foo biz<a l:href="#l21" type="note"><sup>[21]</sup></a>.</p></section><section><title><p>With ampersands</p></title><p>Here’s a link with an ampersand in the URL<a l:href="#l22" type="note"><sup>[22]</sup></a>.</p><p>Here’s a link with an amersand in the link text: AT&amp;T<a l:href="#l23" type="note"><sup>[23]</sup></a>.</p><p>Here’s an inline link<a l:href="#l24" type="note"><sup>[24]</sup></a>.</p><p>Here’s an inline link in pointy braces<a l:href="#l25" type="note"><sup>[25]</sup></a>.</p></section><section><title><p>Autolinks</p></title><p>With an ampersand: http://example.com/?foo=1&amp;bar=2<a l:href="#l26" type="note"><sup>[26]</sup></a></p><p>• In a list?</p><p>• http://example.com/<a l:href="#l27" type="note"><sup>[27]</sup></a></p><p>• It should.</p><p>An e-mail address: nobody@nowhere.net<a l:href="#l28" type="note"><sup>[28]</sup></a></p><cite><p>Blockquoted: http://example.com/<a l:href="#l29" type="note"><sup>[29]</sup></a></p></cite><p>Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code></p><empty-line /><p><code>or here: &lt;http://example.com/&gt;</code></p><empty-line /><empty-line /><p>——————————</p><empty-line /></section></section><section><title><p>Images</p></title><p>From “Voyage dans la Lune” by Georges Melies (1902):</p><image l:href="#image1" l:type="imageType" alt="lalune" title="Voyage dans la Lune" /><p>Here is a movie <image l:href="#image2" l:type="inlineImageType" alt="movie" /> icon.</p><empty-line /><p>——————————</p><empty-line /></section><section><title><p>Footnotes</p></title><p>Here is a footnote reference,<a l:href="#n30" type="note"><sup>[30]</sup></a> and another.<a l:href="#n31" type="note"><sup>[31]</sup></a> This should <emphasis>not</emphasis> be a footnote reference, because it contains a space.[^my note] Here is an inline note.<a l:href="#n32" type="note"><sup>[32]</sup></a></p><cite><p>Notes can go in quotes.<a l:href="#n33" type="note"><sup>[33]</sup></a></p></cite><p> 1. And in list items.<a l:href="#n34" type="note"><sup>[34]</sup></a></p><p>This paragraph should not be part of the note, as it is not indented.</p></section></body><body name="notes"><section id="l1"><title><p>1</p></title><p><code>/url</code></p></section><section id="l2"><title><p>2</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l3"><title><p>3</p></title><p><code>/url/</code></p></section><section id="l4"><title><p>4</p></title><p>title: <code>/url/</code></p></section><section id="l5"><title><p>5</p></title><p>title preceded by two spaces: <code>/url/</code></p></section><section id="l6"><title><p>6</p></title><p>title preceded by a tab: <code>/url/</code></p></section><section id="l7"><title><p>7</p></title><p>title with &quot;quotes&quot; in it: <code>/url/</code></p></section><section id="l8"><title><p>8</p></title><p>title with single quotes: <code>/url/</code></p></section><section id="l9"><title><p>9</p></title><p><code>/url/with_underscore</code></p></section><section id="l10"><title><p>10</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l11"><title><p>11</p></title><p><code></code></p></section><section id="l12"><title><p>12</p></title><p><code>/url/</code></p></section><section id="l13"><title><p>13</p></title><p><code>/url/</code></p></section><section id="l14"><title><p>14</p></title><p><code>/url/</code></p></section><section id="l15"><title><p>15</p></title><p><code>/url/</code></p></section><section id="l16"><title><p>16</p></title><p><code>/url/</code></p></section><section id="l17"><title><p>17</p></title><p><code>/url</code></p></section><section id="l18"><title><p>18</p></title><p><code>/url</code></p></section><section id="l19"><title><p>19</p></title><p><code>/url</code></p></section><section id="l20"><title><p>20</p></title><p>Title with &quot;quotes&quot; inside: <code>/url/</code></p></section><section id="l21"><title><p>21</p></title><p>Title with &quot;quote&quot; inside: <code>/url/</code></p></section><section id="l22"><title><p>22</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l23"><title><p>23</p></title><p>AT&amp;T: <code>http://att.com/</code></p></section><section id="l24"><title><p>24</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l25"><title><p>25</p></title><p><code>/script?foo=1&amp;bar=2</code></p></section><section id="l26"><title><p>26</p></title><p><code>http://example.com/?foo=1&amp;bar=2</code></p></section><section id="l27"><title><p>27</p></title><p><code>http://example.com/</code></p></section><section id="l28"><title><p>28</p></title><p><code>mailto:nobody@nowhere.net</code></p></section><section id="l29"><title><p>29</p></title><p><code>http://example.com/</code></p></section><section id="n30"><title><p>30</p></title><p>Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.</p></section><section id="n31"><title><p>31</p></title><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><empty-line /><p><code> { &lt;code&gt; }</code></p><empty-line /><p>If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.</p></section><section id="n32"><title><p>32</p></title><p>This is <emphasis>easier</emphasis> to type. Inline notes may contain links<a l:href="#l32" type="note"><sup>[32]</sup></a> and <code>]</code> verbatim characters, as well as [bracketed text].</p></section><section id="n33"><title><p>33</p></title><p>In quote.</p></section><section id="n34"><title><p>34</p></title><p>In list.</p></section></body><binary id="image2" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEASABIAAD//gBQVGhpcyBhcnQgaXMgaW4gdGhlIHB1YmxpYyBkb21haW4uIEtldmluIEh1Z2hlcywga2V2aW5oQGVpdC5jb20sIFNlcHRlbWJlciAxOTk1/9sAQwABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/9sAQwEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEB/8AAEQgAFgAUAwEiAAIRAQMRAf/EABoAAQACAwEAAAAAAAAAAAAAAAAICQUGCgf/xAAjEAABBQEAAwABBQAAAAAAAAAGAwQFBwgCAAEJChEVOXa3/8QAFgEBAQEAAAAAAAAAAAAAAAAABggA/8QAJhEBAAECBQEJAAAAAAAAAAAAAQIAAwQFBhEhszE0NlFUcXR1tP/aAAwDAQACEQMRAD8AqQzziPNmpiqnIO1q4H+WkB84MdlzRSuM82/jVw/JCORtRmQz5d2VTy6WmS2eSYx3U/qkSRbgFsqRzH2Is4/mCluXc33vy8xTnJjTNqV/T8LKmkhr8Hq1da2aOvTfIh2CFeNt+GxFBP8AJFdFUbPWh+4FdXV7OtZOMR7mK9lBWNN+JBmMQ5cwmfH8DEFhTZUCRlE6CBq/ds/nBh9oYygeY1L9FnCUnBSN1t+w0l9bNomx1cllsOrL9OCTKtKOIqua6UVjP0dEvTyM7gp/3whbkAD0ScX3r6MLg+C2/XsMhCnJRn/5cVNHyJHiX6JKIFhhqnFeagm9BIgjfcJyNBTZiROBUk6Mp8CJRmT4NWU2MatV7n495DPk/wAbMJSRJOTBDItq0KR5s/nJN7LPW8AJWtYAoKQaDp+u4XShxgXhYcbHoxNTllCwETGQ8ag2jmDVsk8w/wCOp/C/hn+mWV/utpePH+D5wmF39NY6UakjUYR1Dn0YgRM5zQAAAMdfAA4AOAOArjkMNQ3vgm7UKtBR+m9QHFD5tpnDtpy+t2R20gK/OsmFtuDpaL5mVyiT5qdEVAvZci5ch5VoSGKbwlWTBr0RPoZT07av9lHfrXo6yLApWMugKpPM9SV1cDm65s/wkOHZBojoqiM+6GpMSj4FhtayNAUi5H3LfQBG2KWssFoSPuJdKyMLKtpuLi+e3jwFICUg7CSHsNVlYlKdizOTvKdq3KTsG8pQirsAG6vAB5FdhP490U4gfjxi+DedoqO4YftmKdKNulO26jiOv+2Ga/bftVNFXpHtVHrpLpRFJTpP3z77T469++fTx48e4LueE+NY6UKk7UniLP8A7rNf3X6//9k=</binary><binary id="image1" content-type="image/jpeg">/9j/4AAQSkZJRgABAQEAeAB4AAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAD6APoDAREAAhEBAxEB/8QAHAAAAAcBAQAAAAAAAAAAAAAAAQIDBAUGBwAI/8QAPhAAAgEDAwIEBAQFAgUFAAMAAQIDAAQRBRIhBjETIkFRB2FxgRQykaEjQlKxwRXwFjNictEIJEPh8SZTgv/EABcBAQEBAQAAAAAAAAAAAAAAAAABAgT/xAAbEQEBAQEAAwEAAAAAAAAAAAAAARECEiExQf/aAAwDAQACEQMRAD8A2t0YoQpwT2qVzMV+N3UHgrDY2eoM0y58VEbgfp9K1yMRmnuJ5h40jyYHGSeKrWE8u2QAApOMdqGCsmT8h70TAJwMAZx249aKBy4c9vTNUC0zDCgmmmG7Ockjkj1PrUTAjcy5XP0ouCgHae4IomOJHhgIc55PHY0Uk5IXLMcUBQ27n96JYO2MYLebHtRBA7BcMx29sdxQJqwZRtIP+BQKpjHHc+xzigNGoAO/k+nPAoAYlee5oBiGeWySO9AJCgY5PHagFCADzj2GaA2N2TkjA/U0HMwbPPeiyBLDfkkj04FCl1cBMgn6URwYFGySR6D2oAeQDAxnHGKAhU4IbGc+tFwnwDj9aK7f8v2oNu+IHxNvJdXmt9EmKWSqArA/mPvxUxMZNe3Ml1dvNcMzSSEsxPOferJhht/OWyAPc0UfdgDcuM8n50AMCykZFARsngcY/egTcbjnJz9O9AB2kZGSQOcUCX8x83bntQCMruJ4B7D1oCyOGzxtJ9M80CAdg5UjFE0aFJrghLeNpHY4IRdx/QUNWCw6D6q1EZttEvirHAZ4ig/U4qw1b9H+CHVN3Mq6hJaWMJ5ZjJ4hA/7R3P3q3ET+pf8Ap/lWNm03XkkkA8qTW+3PHupP9qxopV78G+s7VSV0+OcAn/kzqSfscVvIKzqPTWu6XKE1LSL+Bhz5oDg/cd6lEZzGwLrtPqrA8frUCJfcw9gfegUjZsEAffNADyHt78UAjCjzDJxRcO5Pw3gwCGOVJQp8ZncMGOeNoxwMY96GCbQffFFcUXKjDDt2NEo+N3yyM5z3okKuqJgIzONoJyuMGi4QfGcqSfXBoYHJx659qKIRnnsfUGgJn/poJYoTIGLY+eDzQFlQK2G/KCTmgbspfO0qce/agPGcR7nHf9vnQFfBPlOc88Gg7uucc/M0Bd208YJJweKAYrea4kKQICRGW5IUYUZJ570DYqcknt3FE0VuVyDzj1oamOlulda6puvC0a0eZVIWSbtGn1Y1NNbX0x8ENH0qL8X1NdtqDoNxiQbIh8u+WpqL70Tc6fcxypouiRadbW8hhLFFXcB7Edz+tNFvEZxkmmgShbA9PlUA+Hgg/wBqDgmBkd6ArJuJBGR7VdEdqWgaVqMfh6hp9pcLj/5Ig2KaKJrvwW6S1EFoLaWwmPIe2fAz81ORTRm3UfwI1mzBbRL+K/ReyS/w3x/b+1Wexmev9O6xoE2zWdOubUDszr5T9G7H9auCJj2n3PPrUXTlGBB2kYx96GlQMjJJHuRRXBgDgk8DtRKH8w4OfYA0SUlIMsFXJ4oujHH8ufnRRGOSNoJNAeFC77F2jPucfvQFEqgY3nj/AKaCUY58wwq54AoCzOmVMke9QeRnGR7ZoEIF7pnaTk49KDpSSwQntQJsGKjgggZ9uDQc4OOe1Am2UCkHOR7dqA8t/cSW8MEkrGGEsUTPCk4zj9KJT3pzQtS6m1aPT9Jh8SVxlmJwqL/UfYURuuhfArR7f8NLrF1cXciKDJCrbI2b7c4+9NGtaRptrpdqltYW0VtAn5Y41wBUodvGjqUdQyn0YZqAIreOBFSFFRF7BQAKA1xcRwKplcJuOBn1NAR7y2ikWMzoZnGVQHJNAuQcD3oBKkD2FBy8jnvQFxnjjmg4rxwKBMqCBtPNA3vbCC+tngvYo54HGGSRQQR9DV0Y91n8DNOvFkuOmZmsrk5PgSNuiY98D1X+1XRhWu6DqWgX72er2j2069t/ZvmD2IoGG7jbnj1FFlB224PB+VClN4DYJHyAojmPGCck8cetCAxgjPp6UaAGKtx6+9ATAXO7nFBw8HHLN+goJhBuj2FeAcnmgNazW8U0vjweODGyqpYrsYjytx3x3oGa5LEEjH9XvQGlgmjjMmQq4HBPfPYgevagG5nhe3tkFuInQHxJQTmQntn0wKBKTlAeDx60DSY+U9zn+mgsnQvROr9Y3W2xi8KxV8SXUnCrjvj1Y/IUR6c6A6H03o6wMVgrSXMoBmuX/NIf8Djt/eiLfjJwO9ZBiOfmKDhktzQAzYBLZ8oyaDF+rOptVv8AUjNZL4tjA/lT+kr3wvqTQX/pi3Y+DqFxKXurmFWAaPaVzg4I/b0oHlxqV7penRTXFu93dPLsESYB2k8n7CgnradLq1WaIOFI/K42sPkRQCg3Kcd6Dgp3d6AdrGg5VxnjmgKWB8uQGxnFAUgKuSefSghuqNC0jXbAWGtxQyJKdsYc4YMf6T6GtDzR8S/hnqfSUz3NvuvNILYSZR5o+ezj/Pb6UGfLzyD/AJoFFySQVBHpQDJ5kGByPahAbWxn5+po0OF3D+XPtQJsNwOe+aAuygmMkebgHnHFALHYpJwSeGz2oGpOJWAI49BQEZlYAHkg4oARVOMvtBIJJ7AUAX6xxSOsUgmjViFcKRuHviiVfvhT8NZuqpk1LVFeHRkPlHZpznsP+n50qPS+mWVppdnFa2cEcFtGu1I41ChR8qyHVxK8cLPDD4kgGVQHBNAa0maaBJGTYzDJXOcUCy5JOaA2OMfoaArkheM7vlQNYNOtoWLJCgLHJwo5NApPKLaNpGRQB6j2oGmnRvcyNd3O/DkeErLhkWgklIdCyZOCRzxzQEeRxhdpUnncBkD5UCxXjJ7+tAlctMsIMLohz5mcZAH09aBQYdQwyAeaAuA7MAQxHH0oG1481nbGVInuWU5Kr+bHrgepoKB1u+o6jqlvBH05NevEBPBK0pQR4I4BHZj+1Bb9IS7lsFtNWtYwDGFYB/EXHqpJ7/WtQYx8VfhGbdZtV6Uh8gy81mpyR6koPb5UGKY4YkeYd88fbFAI5AC98c5oQBb+U9+9GnN5RgDgjOPWgAN3yMfWgAqc91/UUD2RSSRg9+49KCR6e0WfX9WS0icRwgb55WOFijH5nP0FBYNRi6dSR7HRNPmu0hOW1GaXaZMdwBwAP3oynE0XRYrFtV02wS4ECj8dp1wcsE7eJEf39qlFZ616ZttPu7Kbp9Zbi0vYzNCcgjHqoHuKsEp8LPh7P1PqjXerxywaXaviRSu1pWH8g+XuflQemIIY7S3SK3hVIo12pGoAAA7AClEL1N1RH0/oTalcwx+IACLaSQKx59Ppmshv0D1jH1ZbTubU27xkkAnKsuSMg/UUFluLlLaJXETyecKAg554zigXiubeRnSKeJ5FOGVXBIPsaBLULoWkIfw3kYsAqIOSTQJMbpm3oqlmwACeF9yfn+1A+Bx34oE5IY5P+YFbnPIzQKAckHuRQCAQOO1AL8r9KDhkZOT9M8UCcrxgAyYJzwD70CT3Itxm8kgi3fly+P7/AOKA9pskhEkZysnOfeg6RH8w3tgjAHtQRZ1uystSg0m5eRJ2UbHceV8fP3oJkBSAVII9xQFdSRwKDDvjN8L/AMSJte6chxcgFrm1QcSf9aj39x61YMH8Q+CkfhqpQncxBDH5H6VRwXJ/Ke1Am2QchuMYOaNFSAVznB9qAm8f10D2RmX8jDHP3oLbebtA6ej0m2LrfX6LcX7IMskf8kf6HcffIoG8yTadZxSTxCK3kRZUwSFfkruIJ78GhiS6Y1OS3160uZJFWO5bwZtxzuQ8bcfPNMZXvo2wsLnQ9R0q/maJNNv5Yo3bjCuMAHPzqA2jdUan0lF0/ZXcElxp9zE+5WVd/DE71IPPB7H2po1bSNXsdYthLp1ykyEcj+ZT817ioITrnoux6vs1gv5JYnjz4ckZ/Ln5etA+6N0BemdBttMina4WEFfFdQpIJJ7D60E5I4Vo9qnnsQO1A3k0yzeTxhCizZJ3qNpz9RQO449igMSxHGW5NAIwBtUAUAMORkfegMhG3jtQD8+fvQGXJz7UAHuRQA5YDI5FB0qCQA5yaCs2/SFit/Jd3AmvJ2bO64ctt5zwD2oLMilVAUDgcAelAJLbhgZz3oGN9HPIYmhtrWRw2czjt7Y+dA+h3mJS67W9gc0AvuLYANADpkZABHY85oPOnxy+Hx06Z+odGjC2jt/7qBRwjH+cY9D6/OrKMebcceHwfaqCYIyDgZ96GhHOFJI4/WjQpXnsaCz9J6fDqGvRC8OLO3Vri5PB/hqMkfc4H3oDT3UupapcXrKS9zISgDdhnAGPbsKC5aLLBHq9p01c6bbagPE23kpJYhmz5IySAAMj6nNGdRnT2lu3V9vaQQrJDHfCMFj5kAfufsMUFogu5H0jrLUYXK+Lq0aRse/lf/8AOKlFfudagvbnQpNQRmtILydCwPdCQcgMOMZFQanPoeiawBd9M6s9jeKPK1vKQp+RFA4septa6fuFtuqbRrmzx5b+BAdo927A+vsflQXfTr2z1O3W5025juIW/mjOR9KAZI914khaRNo4XdwT9KAl3b2+oWpjMoZWbOVfnI9sUCrXUNssUU8w3sQoJH5jQLvwQQC3NAKvuUPtK54waDg23v6UA7weBnNAIOBigMr+hoOjdZQdhBx3waAVG0Z7UBWfAOQSflQChyNxBAxQRutarb6bHALi9trSW4kEcJnGd7ewFA/j8QEK/IA/MBjmgWDDBB7igj9dupLTTbiaHZ4oQ7A7bQW9ATVgwXSNV6onl8azW6t45pWdxHIxWA/zNtz7A8Glg2S1u7fX+nt0J/H2c4MMhmQoW9GBUjj60g8sfEHpebpDqi4sHLG2Y77eQ486E8fcdvtVFekGW4UfegKVAAKgnFGhuDzxQXbpDTZF6a13UnUqrCOzQ5wGZmXIJ+lE0ppkEK6nJcRWcTW9hA08iKcjcowpye/mxQ0+6VRbC/jvLm48L8LG9y8pIOXxkDnuSTipqHXQMng3es9S3fhn8DbvcZI5Mr/lH700dc3Dad8NtPs4nU6jeXD6nMCwBRF5XOfU8YHrTNJFF1X8RawW1jc4GxTKNrZB385yPkBTFw1stSu7Ni9tPLGSQfK5Aphi8J8UNUm6fn0u72yvJ5fGbuF/39aYYtGgadp9/axXnRetzaXqnhqZI3bEcj4547Ak/X6UxFisPiXe6NMdO65057eQAr+LhUlHHbOPX07UwWXpQ6BqMo1LpgW0sioVI8Qgxk+684qC028M5890Y3kHKbUwF+lA4LDOzu2M4FAOG3DaoI9cntQdJxzQEyR259f/AKoGl5fSQRFo7ZpB/MhYIR9zxQdayyXKb7gqox5Yo2yB9WHc0DPUIWnhWKxkuYFRs5gcKWbPY59KBkx6isVeSGW31JNwHhyOUkA+o8v9qCfjkMo/LJFKqBmRvSgc2swnRyFcYODuXGfpQMtRsLK8vYJL+wjuGiUtHK6hghz6Z7H6UEmCsig84I9RigiruC9t0DaaVmIIHhTOQMeuGwT9qCJ1ywv9T0U29xFFiaVBJGHz5M5ODgYPY/arKJPTtLW1t44i7SKq48w8x+ZPrTRJoipGFQAAdgKgzX47dMJrXSrXkUe6807MykDkp/MP8/aro80FQyZ+tUJ7hvH0x270XQ7KGtXvIk0T4c9P2bIhkvpnvJVfjIxhf7qftRDXpu0/1DpzXltUlkvmWMBI+2zdnn64oYa6yX0XTm0i4jQ3t6wmuV53xov5UPpyeeKyLbpFtZ6Xpmn6TqNq7/ic6pqQRR/DVf8Alq2fTOP0FXBnXU+ox32o3lzeW+JrxlMXHKR9wfbJ/tVWK5f3AnaAjafCTwwcY4BOM/qKKSjA4Dg8j37UHZKkE5P0olSFlcLDdJPbTNBOigjxOVZu3+80Rbbnrq9l0t9I6isRd2rgKpPlZMdyre9An07oupoh1zo2+lea2fMlr+WZFx7ZwwqWDVug/ihDq7R6b1EPwmpMNokPlVj8xng1BqEUe1EAJOMDOc5oDSxq6YYeuaAJF4oCBUQ7mJ45zQHYB14wR86AVjBXyjge1AEcRTHlA9hQE8kbgEohJ5yQM0ETHNqMOr3IZQ9tIMQyEjKt7D3FBLqywRPJKTuxlj3zQI3Ut14e+yhWRj28Q7RjH60EfpF3rU/jLqFrHbS4/hqpJXH19aCRa8jgiVr1xGwXzYyf99qA9tc29/aRXFnKs1vINyOO2KByoxwe9AYocHGKBvdwLcWzxSLuR1KuD6gjBoPHXWujt071Nf6YSSkUnkJ4yp5H7f2rQgWAA3Y+1An4j/1t+tBrHxKuYS+gx24LRx6ZFtI/lz60FY0+/v8ASphNpd68EpXY5AGNvzFF1YOirZbzVrvX9dkNxZWH8eeaY5Lyj8qj7kcVlETqOqXd/HrPUNzcNE16Tbwxf1JkEgD2AA/etBte9R2Oq2cv+p6XHJfBFjgmjkMaRgAAEqO5o1FWfbgjsR8+9AlI5CgEggeoNAq0iug8uD7g80KKmCcZ7fPmjJzJfT/hWtjJvhOPK/OOe49u9A96X1W90/VrRtNkkSfxQF8I5yScdvX6UGidSLpfVFzcvbRiy6kgZBGysFW7B9T7HHNSjU+o9S1iz0e2uNLmX8RYxJ+KgYeVwVGTn5d6gjug/iU3UOt/6TewQpP59skL5B29x/8AYoNHPB78Ggb2l3bXO78PKsoyVyvIBHBFAoSkbfyhn4GfWgTnmWFN7ybAvc4Jz9hQRdx1dp0S3Dw+JJHbDdPIUZUjX3yRz9Bmrgzbqb4x9Oxho4bB751O5HPkXPsc80wQHT/xrJ1IHUbGKO0kdRiBiAgz+YjnsPpTKN/tLy3vLOK5t5klt5F3LKhyCPemAYLuK5XMDEj1OCP71ArGWLMPT0oIbU7h11u2t49OllWWNm/FIRsjI4AI/egfQ2ktpbww2XgxoDl9wJ49cUCHUGv2GixM13Mkcm0squwUH5/SrgxDW/jFcXOteHb3otrKEEiRISRM3zGc49v1qDT+gfiBpvV7y2unxTxywRhz4ozuHbOR2+9Bmf8A6kNIEWpaZqiooEqtBIR6kHI/atfRjDEt3AKjgVQjug9j+lQWh72e/htTOzyeCnhHPomeMYoJvQum7vVD47K9jpsQBkvZ5NoAHcgUAa7rKamE0Lp9Xh0G1OZZTwZSO8jn9cCsivdS38F9cJDZIY7G2URxKe5x/MT7nNaEKrENwAFPPlosFwS2cd/cc0UlIm3JOeKDo2LH+UA0SjgDk98URzPiJ2449e/NAbS7v8PdpKkpikQ5WQLkqccGgmYNQmXWLeQLG9wVRQVPlcj+Yn3xQa98OviAjz3WjdXSpFdliEuJCNjDtsJ7enepRdel+kdL0rqOTVdIsoYklV1dixO3nunpg9jUCnU3WMeka5b2EUcl3JInmigQs6ZPlJAHY8+vpQP9O1m3nthNo0cTwM2JDwoVj6H5gd6CbhtUiVn8TcXO4ktkZ+We1BAf8Z6fZ2uqXWpyxQrbStGseQzMB2IA961B59+IHXmodXal+HsPFh04HbHCo25+bY/zQWv4f/CCxvII73qC8iuXYb1tYZeF9txHf6U3BatX+DvSl86x6cr2dwjbnEUmcj6Enj6U8hLdJdEX/SmowJp2tTT6Oc+La3HO0442+3NBf1LmRUjjQAfmc+nyHvWQockYyQcY3CgaabaPZxGNnaUFi3mPb6f+KA2q3RstNurnBxDE0mPfCk1YPMemaP1L8RtYN9fJPc2aMUaVmCKg54H0z6VRYendf6Z6T1W56a6j6fgfwJyguhGJmPzbIzjHtSjTn0zSunbi01fSkt9Os5GAmWNCDOGxtXb6HnNZEZ8etOF90DPKFy1rKk3zAzg/3rXI8u7zvOTg4zVoTLDJ81QWDTb2SwuvFgcrkbXwM5H0PFGqsjpd6+kcT61Nc2ieb8OikFc/9PA+WfSjKA1nWBzpFlZ/hLWM4KH8zsPVj6mghN4IyQRk5NGo5BkFmyAfSgVjChdpGO/FAXYpOHLBe/FAQqoBJbA9sUBGxgtgEj/eaCf6DGjt1TZf8RNGumKS7mQZQkDIB+WaMrf8Ub/ovV7V20JIYL62K4khhCLOCcEcAdu9BmCuEQvxvyFUg42+v+/rQaj0zax/EXRY9Nns0t9TtM+BqCKAjEclXA98jn+1Si7Cz6u6O0tLjTrxLu2tQJJrDwcKE/m2M2SfeoLrpupDV9Mh1OytUS2vIN8m4BZQf6T7+vPpj50GfdK9L6rJqk1y1y0elRDKRqdjHHoyDhjx39e9BZr7fagW0j3kul3iETRqHkeF8ZBUjkZIxjtk5rQ86dW6r+O1OcW0UtvaRsY4oWfLKBxz7k/5NA46P6X1rqS6WPS7V9v88rAqi/f3oN46X6C1DSotkus+BIwKl8hn2+3PapROXPT2t20bPY6kJ5UGYmbIfIHGW5z68VBI6DrzzWSrrAjtrwFUbDja5OBlfuaCbluJLeNwIpLiVF3bVXAP0Pv8qBxLO8cYcW7vnuqkAigNFKs8CyxlwG/lcYI+1A31ayF/pt1auSFmiaM/LIxVgwfoO413o3qqfSLyUSwodogAyZVGcbPTPr71aNDvendJ6wtbu7Fi1lezK0bS4VZMjtnFZE0bC5u9Jh0qRAr2yw4uWx59vBI44PegN1tpbap0lqOk2sipLPB4aFsnHbBNOR5A1exFhqFxbeKkngyMhdOxIPcVuhiZFz/zBUEwcKvYnP6fWi0+6chjn6h062uATFLcRrIMnzAsO9EehNR+GvTV3GUh0+O2YsGaWHIf9amjIfib0no3S0VtFY3M000zMzLJtLKvvkenyx96oz0rwNjA8cj2osFLbVAbOc9jRQiXOAwxnj3oBlAxwDj37UDY+vHOQeTQBIdqjcPMfnQwJclWyBgCjJBFeefw4VaVycBUGST2wAKD0L8H9C1rSIILjWLSCytY1lZASVnlL4PI/wD8+vvUo1uwbxI5GkjdVc7isvOBjtj2qBWKFZiQ8CJCB5FHYj5jHFArDbQ20ey3RY1HOAOPsKCH1u61CPSLt9MtlXUHUrbCbJBbPdtvYetXR5T1y2udD6lni1ErJdJLvlK4wWOCePvVgsV/8Sr67UW1vA0NiowIonMe4+7FeT9ARQRmodWa9EYpPBhs1Tygw26rk9xknkn70EjonxZ17TXjAeKTkZ3L+YZ7N8vpSjX+lOpNM6umgkMG3EgBV1DYbG4kewz2NZGkC43CP8MPFBONysMAD50DaHVH8S6N1a+BaxMUjd280pA5wPb296DrXWLK9WNoJdtwybxDKPDcAnHIoJBifTBzzmgaz2UFzPFNNbwvLCcxuyglT7igdRRKg8qAZ5JAAzQEnuYoHiSWQIZW2ID/ADH2H6UERr12BY6hueIQJaO7SK/nHfnHtx3pyPGWoN4jynuCfU963RF+DL/UtQWTkjaWY/8ATnHFGql+j1VerdJY8r+KiJz/ANwoy9C/EjqSbpbRY723RJC8ojIcZ4IJ/wAVkecer9en1+9FzeLCCq4URjgDP7mtLhteadBY2kMczyHUpcO0YxtiUjgH/q9celAiLy1kjCX1ruyMLNGdrj0+h+lE0+t+kNQltJ7yKS3jgiTxUFw/hySp7qp70NV6YEBgWUNjBoaKeAODnHrRoVgDnBP0ozpxZ2f4y5trVeGuJFiBPpk4zQep9C0LTembS30fQbWP8ZsDyTugZgf6ix9fYZpbgmbXSmXULaa6kMzpltzcjJ//AGpaLCY1CDsF74PrUCgHY0HbSx7Z96BGUfxB2xjtQZ11t0Tb6jNfyw2wM18gV5AcBdpzyPnV0Yp1F0o/TEczXjXaTOQYpIk3QlT3B9Rj0zVl0VKbVppImheUSwbsgFfXHc0De0tri/ujFYQSSyfmKopPHqaDV/g9p+padr/gkSRTzKu0kZRlPLYPbOPf2pg9GWzRCMJAFxH5do4wayKX1z/G0CdzqLWRkiaTxQBLudclQvovbv3oMU/4Z67uwnUAt3u1Zw42yhmx3/Ln8v0oN86L1d00i3i1UiGQIocNnEbnkqT2xgiguEbI4DIysp7EHNAZnxQQ/Usksej3EsCl5EUthR5sY52/Mjigr6Qrp3R15LqEcIlmgdpFGAsY2navPJApyPJtwd8rnGBuJz6Gt0MzGSTyf0qCwSKA5ZsAjnn2otTXQYj/AOMNIDqCrXUZwf8AuGDRG6fF6Gyfo6+ub0CR4EPgIScLIeAcfc1keatN0661a+S3sYTPKzAbV9B7/StLrQ/iXp9pYLp8elWsUM11AzXMqt53I7g7j244oiB6W6Tn6j2TeAy2FspTeB+Z+/8AmgtnWlvpdl1Dp1pq07Ja20GFQpuDHHAwPf39KDHriVTKSPOCeBnHHtQGsrG5v5pfwcTOIlMjgEeVfck0XRIreS7uUigRpJXOEVe5PtRE/wBJ9HaxqvUcdhNFJp0lviaSWVcMgzxgdySeBipo9T6O8NppUJ1K4iW5KgSvIyqxb5jPH0paJm1NvKivE6Mp7MpyP1FQLRTwy58F0cjuAckfagOTtO3+Y8igMWCIWbOPlzQNhNBOWEbq5Q+YKc4+tAD7JEZgQfXj0oI/VtIttXsZLW5hRopByCP/ADVlGRa78Erae63aXK1tG3LAncM/Kmh10l8IZdBv4rxtTE0yggJsyoz6/P0po0zSNKEMdo9xGnjxuzkqMAEgjj7GmialjWQMgyCRyQcGoITqHT7q/a30+G2jFmwLSzl8GPBGFA9c5NBPRwJDbpHCipEi4CjtigqfWltqCaG8WhNbxyzOBIs8W8FcY4+dWQQ/wtuZdIGqadrknhy2u2QyOSEZOeRngY+XvTBZZevOmhC8janbqiZ53Zzj2FMFcs+sh1ZqsFrp8UkGkrlpbh+DNzhVX5Z5NQTfXyWUXSV2t+wW3EZ5I4HHt61eYPI0mA5C9snFaoLsPv8AvUEk5JcA8cZG480WnOlXX4PVLO4yQ0cyP244Yf8AiiPUfUump1B0/c2O8xfi4v8AmL3UcGpgw/SujNX0Trj8PpckimOMvHO/kEg9Rjs3PpV0aFq/Qqa1ZJ/qcrverEqNOwGM+uMfemiVtrKbQdMNjp9rvtkhPht6mU5yT8u1BkvXg1qXUtOvddgRY1R3j2YHiMvZSD27CgzSCyuNQ1KK0giL3Mz4VAOc/wDignoNNOnaHeiW8hgkku/Al2+Ziqgn09M0ETp0qpqSmGKOdFcEeLwMfPHag3JLuCRtPmQWsDhNphtVAcn1w3BPFSwDdWGpX1/OYdOtbbSrlQ80szHdn0GR24/c1AbWemdatLbTJdGvJIJypDQwMV3exwOPatSz9Ei/R+txy2mr3evyHV4miWIDhGwwyGA7nGRS2YNZAUBWYDdjGayEvxMYB3nYu4KCfU+woG93c2enWs1xcPFDCp8zEgDPzq4GGgz22saS1zZSZhkdsFePXt86YHWmySeLNDMYikZ4YNlvvUD+VARxQJqgwRQHUAAe2O1AWOFRM8mDlgB37fagb6reXFt4ItLZJnZsuWfaI0Hdjwcn2FAz0nWX1i4u4xY3VpFbv4eZ1x4vGdy/KgkriN2aMRlQoOW3DOR/5qwYr1P1tp2pdS3WnanKkGh24kRl2eaYgcb/AFxnnAqiv9Jno0dRLJPbtdQtkNPIALaMnODsPPpSjbdK0DTbWQXui+Gsco3BU5hPP5gPT7VkU74t6PZHpq/1N5ZZbwrtRnmOwDPOFJwPsK1xR5ybudw788VaC5X2WoJRULSBpAe5PA/aiinAZnHck4A70THq/Qr23/4Y0u4lmCpLBGA7epxjH60Du+WGOBvFlFuWOFcYyCfbPrUojri6k06xX8PFNfBUJ3ltzM3scVBjfVvVXVNit5dapNDZGQGK3shjeAe7YHIwAOT3zVggNTiu+orrR4p7m+upJFR7h3TPhggDaoBwRjnPH5hV0af0xotnoD3l5dWdrY2YjGLhwPEHoef996CC6m0HpuPpk3Wny2s9sJPHJ3AeI2D39T37UGU9QTDULuGPSLPwIyoVIYk2lj6/X70G2/DPp0hVudRuBLcwxhRGkeEjB9M+p96DSLprVHiieaAE+YxHkke4H1qUOIBawL4uAuc8nvj71AwjRtQ1eO78QNp9odyLju/qT8uf70Gb6r8SpLzryy0vp+4NxYSSCEswI2u2Rn3OOD9qC4dVamen9NlaC7tUaIFvCmnHiy4HJXJxnOeDVwed+rOvLnqSyWO4jZSru/kc7ck+30GKosXw2+KmqaDJDY3jR3OmqNoRhtZAP6SP7Ggtmt63qbTJ1XLazJpslwBFblypEOAA7L2OWANS+xrnR2vW3UmjJeWp8wJSRf6WHeoJdSPMCRmgMq8DmgBpNsgUIxBGSccD70DczmS8MDWoe28MN4+f588rj980CktuJZYpFdlKZ4B4OfegQ1hpIrVjbsRMBhBj8x9qsHnX/hm36y1O/u9V1ddPmS6aD8OkQdyxOSe4OMmqLUvwQsYY4Xjv7m4YEEhwFyMY7fXB5pRbvhp0jqfSMV7b6jqZvLGQAwxAEBDk54PuD6VkVb49a5DBpiaNaeF/FIaQDumOwpzMGDEZQZ5+VboR8In1I+9QWDY6gFn7jjHpQhtJEFbAGBnijT0P8H7qPVOh47a42yNaymPBOcDupoykep+m73V7g/8Av2itQowvJIx6j5/OpRjfUWrax051RPY6LqFy8YACkebO4Z7HjNWCY0ToW2utJbqPreW5na4O4R78cehY9+fQVKLX05p1ro97awC4kX8VFmJLeEKdoyfOxJPbHbHYVAz0rqKPWNauri9t1ktJgILYgEiNFJ/Op9STmrBBdeaFCo0y3jt444DI3jLE204Y5DD+9UPPhv0NaRtPq99mSLOy22nOfdh75oNC0vT7m1uJGvGiii3AW8UDbQAeDu9zUohLlhouqap1VciF4I1FtbxSthtobBIPuTn7VBJ2vUth1TYk2ULi9iALwyKQYz6Z9CM0Ft060/DWEcDHe2Mucdye9BFW3SekWt3LPb2cUTsd2UGCG9x7VYMzufhzdX/WmoXj+BPpx3I7XZMmXYckc8EVRKaP8I+nXikLQuxOQSTnBzj6UEjonw90XSrq3S3s7dplJcl1EhGDx396lFx1TQ4NVjaC7UNCU2lAO/8AvNWDCLp9X+E/WgWImXSp2LRq7eSRT3B9iP8AFSjd9P1+21TRodVsMS2rLmTbyUGOePXFQSltcLcW0c1vh4mXcjDswoDLdRm4FvISsgXeTghDzjAPbPyzmgVFxCzuiOC0WN3sM+5oDqySJmNg3rx7UFb60tNUubGJdFdEvhIdryflUFSM49TVgyTQenJemOorf/U4H1Fpp1edAh/hOQTuQ9375JA4q0bnbPBcxxT20wkjKkqYzlT9ayGWu38um2MbLEJ7iRtoUds+/wAgBzQeW/iHqi6j1PdzeL44HkL9txHtWhVUOVyvHNB2F9zQT8hUAhAdp5FCG0mSAzE4HGDRppvwL1bwOpJbEsFiuYyVX3deR98Zoy2ZtRgmjkSRZocEp51K7se3vUow/rfpFE124mVpfD4mk2MWdCc4A+VWCH1281/UmFnpklzPYRFBEG8uGC4yQfcn9alGgaJo95rRsbi53WaxwrHOm7BjYcHnvz/moJaw07pXSI5IW1K0CQnDhpAWB9R796CudY62msTRW+gadI8KnDXMkLLv9MA8HGOKC3dAXF1dRfh75f41moi4G0AdwcfTj7UFhv7RjqMBV5AJFZHkR8FRjIx6CgpXVNjJ1JqNn07p26CztSJLlpIydyj2J+fGaC+afplrazqLa3SKNIggx3IHYUEsBk4wQc4oK11L1z070/M9rql6wuVA3QopLcjNBDwfFboqeSO2W7kQNxuaEhQfnQLt8TuireVoV1UeXnckTFT9DigHRuv+mbu9ZV1W3Nyc4IRlVl9O47/KgtU+s6baw+JcX1umRkAuM/p3oK/1t0rYdX6cqXKESqN8Ug/Mp9P1qwZ702mo9GdUTWJsmOn3EY8CAORGXJAwScjJ5q0bJDNLb6YklxbKsgA3wwndg9sDtWQN3aw3ZKTwLLEQOGORn6ehoG1vYAw3FikRt7JSuH3Hc/GSc5P0oHn4aO2uGuYyiose044wBQIm6F1dwfh5ARs8R8L2BHGfnQHv9PS4PjxrGLtFKxysm4qD3oCxboIIo7e1jhQHzAYUJ8wP8VYM56j1ktaal1BMrS2sAaK1OQDD6eUepY9yfQVR5zv7hrmaSaRtzyHJY0DcE4BPIPb5UBwOO4oJYzFvzEYHAH9XvQhNZN7AEgDOSDRo/wBA1SXRdVtNQgb/AJUgfBHcZ/8AGaGPVlhPbarZ2t5CEeORBKje2RUrI1zYxTBhMinIwcjvUEcugWkO4AMisMEA8N69u3yoERrOhWNxNYy6hapcxAeJHM+D8u9ASLStLlm/EWdpZyxy+Z3RQ3I5B44oJKTT4blFWSNBEOeBg5+goFYbOK1TKhIxnIbGMH50Cpcyo6AMrIcM2OD68Ggb6Lbbllu5Cd88hYBu6rztWglSNkfm4P70Gaat8Rba96w0vp3R2mhufxyi4kO3YyDOV9+f8VYMw+P0cP8Ax4JVuEKzW8bEr5tuMj0+lUZ7Y2X4288GK+towRlZXYqv9uKCQi6YmbT2u11GzaJWKnYxbBB49KCFnhubdiwL+U8OhP60ElpXUFxY6nDdXQF0qYbZKxwT9vWg3npb42aHcmC11C3uLSQjEkpIdQfr3xUondP6x6e6tv7e101hczRzrNtaFiFC/wAxPYHtUF+lj8bYCTgMG59cUC4OBQQOo2eoXepFTeL/AKYQN1sEwWx6Fu+DQLX2kw3Ok3Vjas9qJ48Exd1PHb9KCE6R0G86Ut7mK71KK4gklM7TyKRIBjtjtjj96AOreudJsrMJbXksk8jBCbVdzRjONxBHP/3QQ9x1jcWGkERWWqXdpMPCt7x4wfFOOWPbA+fAqwZr8TJ9Qbp2ymvEjsrSTEVvawyHz45Lv6E4wPqaoyl8g91OKDlYEc8mgKW5PH7UE80f8PPHl7gDFAZkUjawUIQG8w5ouknAUbl9Dg59KK1X4Z9XXFvo8mlRXax3KHfBG8Rk3qe6jHOc54+dMZO7jr/qK8vWtba4tYu38TwvDOMc8N60wPLbrW10PS7pnvrnUtbAKobgBUUk9jg8f/lMC2rydMdRSaRqWoLEbx4UefwxkL2BVvvn9Klgv3Tp0lPxFno6wJ4IVmEOMEHsf2xUD2e4ks7n+NGDaCMu8q8lCMcEfPNA6tW/EwrMybEYZUHnI9Cf/FAzu7G4LXTWs38SRNqhs4Bz3z9KCO6x07UNT6altNMvEs7xkC7nPlI9R2/egwbrDT+r+kupLCeK9nu3KBYGRy+QvdWFWCU6avtA6h1iKDqLRhpmpvkxz2p8JGb3z7k557VRX77TdHteuPBut401CAouyXGcdvmASaC069030brYaay/CwPFwWspRErfUN7UGZX2hWSiY6ZrMc0CvhUlBUk/UcGgiLq2mtG8F54yDwfDfIoGkrRsSZXwOB2zmgsvw06XHVfUcFvI22xQ753Ze4H8v3OBUo9a6XodjpltHbabDHZIhVsQqBuA9DxznFQTQUe5oDYGMnn7UEbpV3JqDyz+BJFbBtsXiDBf/qx6CgDXL42cSRwGM3UzBQrHGFzy32oG2i2kKTSI80lzMow0rqQoyew+3tQO59KtJJRI9rEzgg7igz3z/egZ6paJdGGwW4eBXy7pGeXUdwT6A5qwebPjJrcOr9TvbWZQ2Onr+Gi2nIJHcj7+vyqigOuRk+vtxQAqEk4BU0ABj7j96CzzKxYD0GeM0CQG3OMAjkfOgbSZwzE4PJyfWi6caTdzaffW95akrPFIrLg/tRHpGzs9C6t0W31FrO3Y43MrcbH9c/eloZ6v0JpWoKlrHHBbScSFEHYc5Pz71NDXUoJrK1g0dvw9qsspW3nXaN6KMrHnH5ieSfan0U3Rr1uidaRbiwk8BUSS6naQkjc3ZcHaRnn70wbja6lZX+nw3NvMksM+FXnPJ9DUCeoXj2hSG2t2km7op4U/f/FAvHaNePb3N0jRzRA7VD8Akc9u/FAvcxnawZQ3HYtjJoKfDFAdeub6Vo1dSULIBtTbgYOfU8jNWUVvrm5ih0m1urixhlsI5HJliOwR5/LkkHHJPamjHdQ0HWdemlutN0+YWBYtC0rHDhjwVz3zWgx1n4e9U6QE8XT5Zd//APR5se9XBXbjS9S0zAvbO5tyWKAOhG4/KpQ3ZHXO5JFK98qRUGhfCbph77Uvx91pv463wVjR0LR7s483796WjW7rTrXpHWrSW2YK7lmXTbaIFpCRjjHOOSeeBipaNLtXuIre3R43lnkGXYADZnnmoH6Dkbzn6UDGWe9a/hKG3jsW8riQMJS3svp86B6zgMQmDtGT8qDNb6XUpOoPx72tzOkjFYowOduDwDjj70Gg6Wsq2KNeAJKRuKk52fIn5DvVkENrvW+iaSAsl0txI2Asdud5Yk4A4pgzv4l9ST6JZSXbyyprWpw+FFa5G21gz5icfzH3pgwCSQlh688+tUEwjjngZ7UHAHuWAHpn+1AXj5frQWXOGBZcKSe3c/rQIyAtnI27eBj/ADQIMAuH8vHBB9DQwVpPLjOckEZ/ahi9/Czqj/S9VhtLm6aG1uZFUsT5VOfX5Gpg9GiNJArxsrxsv1BHypYGF7pljeG3kvLZSlqzNGGxhSRjP6GoG1yLUWiWc2nSPA4KJGItyYHYHHarop3wu0jWYNUvzriNBp8ErraRMANxJ/N7nA7ZqDUHgSQLvAbacjI7H3oOuIFuYzGS68jJRyp4+lA0m0yDwGjiTw3bzBwTuDe+TQVbV+mLmW1NtbSok9weZiC2zPLEZ+/FBM6Xo40/TYdL8Jr21G4vJcuCck55HbFWUKQ/h4tR/DTz2o8TK21qmMgKOf8AfpmrokljG1i5BHI57D5VNorut9Lab1LA638W6H8sboNrqQckq3pntV0RWsfD6K7SGC3vTFahQJY2iVmkI9d+Mimie0Hp2DQ7AQacio3JZgqjcT3zxk1KHGldPWtnqMupS5uNTmGGnk5KjGNqf0r8qgmkhVGcquGblm96BDUZZYLGVrdN8+MIvux7UGKTdXdbaRrFvbaxbWN4d58BmwCjHPORycLx2q4LNe9S9TdN6I13qkWmzSXdwBCGlO4hiMKAB2A9ag0WySQwpLLtMjDcQBhVz6CgoHxF17XbnUYunulgsUsu4TTvjIUAEhR+x4qwZwtkOi7651PXJobm4tohHbQhdgecjnaPZeOfeqMy1vWLvWNQlvb+ZpJpWyT2A9gB6Cgjy5AO4A5oAGRgBR39aA7Z8MkFtxPY0AbV9UGfpQWhj5TkBQGxuBoEGG1iQCyHvj1oELgSkK6oRnIBIxzRdJ28Q3+fHiAds96LoH3AF1wCfyijNbF8JviI1rbQ6Pq/iSopxFOx5Uf0n3qUbWQk8II2SRyDPuCDUHMpSIiJQSBwDwKAgTxApnEbyIQ+APyn0+9A5B3AgfmoEWgcb3VlMpGFYjt+negSs7zxH/C3RWO9UElM8SAHG5fl/agNdXcEbJAZ1WadvDQDJO7Gf7c0ED1dqWv2enzw6Rb24nZfJd3EwREHqxyMZHzOKBbT7H8PZWTK5uZ9o3Xm1SzEry5PsT7UFF+JnUezSZ9LttRs2km2m5KSFWXDZI491AyBzVwK6J8T7CRtPjee0tbaGAtdNISdoXgLEo5JJxyfSmC6aF1fo2vELZXDJOxwkMybHYe4HtUFiJWJd8rKqjuTQcZV8SNI0dy43BlGVA+ZoBniE0RU7tp77Tg5zQUv4hNrU2tdNWOhylPEnaS5UHGYlAzn5cn74oHGt6l0z07k6nJC123HhKPFlbPptGTj9q0Kx0XMvU+ty6vqQtpWlZo4LOdGDWsak8Aflycgk+v2qC8a1q8OnaXLPOz2kCIWkZ+CqjgYx6n0xTBkmp9Sabp0KdRyI5vJkaGw08MVKIDw8jA557896QY1q2o3eqXr3N7O8skjnlnzgn5e1UMCGV/MOM0BJFOVwfX0oFtgZTjkg8UBtpOeO1B3hg85FBZXVMM+VJAA2+h96BO4IMJ/p7qvuKBKacmOKB5CYYx5UzgDPfHzoGwD5OApJHAHrQEAk8NWdNpx+XdkA0AIGhkGWOQcgg8UGw/DP4kmwhi07WCTZqAiSbstGc4+pFKNvs5o7q2Sa3kWaJxkOp4NZDOHUh/qL2k8LW78eG7kbZv+0+/yoEZp7fUpX/BXpgvYZTCSRtO7vtwe/vQdY6jeyatPp91FEPw8aSNMoYbi2cADt6Z70DS60KW7luJdV1JniJzBtURG2b0KN7+/vQKSWUWnLLqN3cSLP4ex5Y8jxiPykr23+nzzigpXUPVOu6Vqmmf8UWttb9OXDqkjRnfI3H849uRkDOKC0axLFr+nLB0rrUMM0bqCIGGGX1AH09qsGc9UfBiTV9Vhu9Pu5oPGLNeG6bczN7jHvVEr058Gre3sLeDVrmOdo3LmSFNjEH+XdntQXO51XQOl5YrCKGWa8SMYS3tzMyLjjJHb9alDqz1S5ktJ7nVdLmSVDiOONfEMiE4Xy+h9xUDm11CaTxEOn3VmpHFxKFCr9s5GPmKAus6jb9M6RJf3c88yxpjcxL7uM5OO3HrQVTSupoOuYdZMTSpptriNFtXKXDA/Pjhs9h2xQOJ7Xpnpa2S91WK2swqjbGw3ysfcnuxrQsGmapYvpwvra1FtDL52Mi+Gx49sZoMb+LXV0t+jWl3OYLGTO2zjx4h2nyszHsG4/Sgxt5ZJmEsjl3PB3GgSlyXBxkDnNADseB2PsaA8SoXQyFgmQCV70B5R/EIjYmPJxnvigEKcYDfrQF2/X9aCwqC7l2zwfT/FAJJ5747E5oGTqZArKOfccftQHZWwmOD23Z4NAEkTEBmwR7g5AoG7KSSE5HyFAMTyQsMHa/cEcEc5oL58P+v7rppdryPNAXx+GfsQe7Z9D2/Wg3zSdX0fqzT08F433eYwscOpHt9PcVkQPW632mX9vfWdrbXiRgrIdu2eHIwGD57+nIoKdc/ELVdC0u5afp27SUtta5vJMMzk+UDjzYHtQWDpj4gxXmif/wAitXZkGZzFGW8MehZO+PmM0Fibr/poWQmF6xXA2xmFg59sKRk0C2nQP1KFvdb0vwIUJNtDKcsVP8zD0Jx2oJDTNA0vR5p7qzs44pJOXkUc/SgNfa/pNvbF5L2JgTsCo2WJzjGKA1jcNcxOF/m/I0zbt4+gxgenNA5s7CCxWWYQxpNLgyMiY3nt2oHajcuexAoEL1C1uyFkVHO1ixHb17/KgwT4rdXWep6oul2OpywaTYqVLxDyySDjaM9x6Z+tWDPdB1TW7Wa9sumpGlursqMQRlpXwd3BA4571RcdN0i41G7h/wBSmNxqdkwn1O6u5/4cAXlYgcnngE/pQNvih8S211obHRyYbWInfJG/Ex9MD2+tBmNzcTXTtJcSSSSHH5jngDAH0oEdxbg5A9wKAzPwO+fegSLfLJoFoR5fUfegXOcHGAT8qAM+XaBzQCCwGDuyPlQWJpV37Q5TIweM7u/f9qA9vNYpFML2KaR8YiaJgAh55PvQRvnYoqA+MThcDnPai4PKWQlH3K6tggjnPaiEmz4ZznBPfFAVWG0AZDH1z2HzoE7lhv8AJIHI/mGRQI8AEeuOMGgndN6pu7V4RJLKY4WDLhypXj0oNL6d+MMS4ttetDdQgDNwAPEwPRh2NZGkabrvTXVZiexvba5aI+ILWZQG3Y4IDdvtQScvTdjK8chtFjkQ+VlYgqPXGKA17daV07apJrV9CsZbELTgbu3YY78UEHf9evJ4K9P6JqGoiR1XxjCUjAJ5OT3NBM9YdSWPTenwy3t7bWbSuBunUthfUhRyT+1BA2vXnS/jGdeo9LnIHljeLwSCe5zgmgejrOz1S3kGhazoaXYGAJ5Sw3e38uaCsJfX02rPD1XfXtvcCXdBJGjLbOO+EK88Y7nIoLB1H1Bb6WkN1ddSQ29io/5MZEjzt7DGTjj2FXNGUfEH4wRaxCtnp2kwGGM7llvBvIOO4XOAe/fNMwZbqusalfLBHfzSvFH+SIgKo+igYqiwWfWV30rpp03p6exJnUPJexQnxuR+Ulu2PkKCrT6jcSiTxZnbxCWcFidxPJJ96BBDlQ35fbFAbahBHJIGO+KAIwg5YnB455oDkKcbW7UAOowSMjOORQcCVXPp+9AqDkHcDmgMNpHPcUBTuzQWCJXcFvKR2Y0CMiqjnz4UcH/6oG8gKluwxyAfSjQ6ylEJBJfv37/OiYQMjbjkZXOSP/FEELAEkNn1waBCXdjORnPoc80CZeTb5wQe2BQAm4y7jlhjvQcWO3cW4GB7ZpgGC5a3uUeNyGQ5GCR+45pgt+l/EzqLTgxj1O5Zc4CSOXCj70wOE+Jd/Pq0V7qVvb3bISAWUBhnuc+/2pgvkHx0soLaNIdKkEiqR5yDg47cYpgresfELSNc1n8VrFtAw2ZBiiywwcgeb14x2xTBYNA13ozUo/GOqWVizDc1nf6crIh/7wOf1rOURvVupdE6ncpFeakiSWsZdbjSLfw1Zs+VVyMHA75xWsFDHU0idTJdf65rT28YKpPvHjKp9Bk49qYK/rGpXF/qU9zPdyzyyMSJJAAx9ifnVlwNZ7vxYEh8GAEHO8DDH5H5U0IPK8jHxSzFQAMnOKgJkFwPT6UBlAII5z3zQCjnA5OKBXeuAT9KABMA208DtxQHRhzgUC3KjJx9z2oAP6/L3NAHC8Hg/XNAcNtGe4oEy5yeaCdLk7yx2qQCAO1AmXZSSexHbPNAhJuLJkgjvzRonuAJy2cd8UCbyOi453Dj7GiYTZyVPPl74oYLJIyq68EH3Gf3oYTDEjLbiP1FEDHOUOdgOfXIBFAm77j5Mnng/WgLI5UE8Eg9iO9AnuJbuQx5wOBQFRxuIbOc54PrQK28ws76F722EyI4d4HJUOPb35yKBm8oeQsi4BPbPb71RyYIHmPGRg00GRsbsHIPY0Bg52AEEseBUCQJyOPXtQDtcdvvjtQCQ/GBwKAuXU4PrQBvZE5IGeO1AffjBJ57UBvEO045HagFWAAzktQKIzBeMg0C5kz5mOG/WgMrDJJ7jmgEnIyOccYoA3cEMRj05oC7/wDeBQTduzEoNxwcZGaAJOWfPNAlISVOT60aIQfkj+amgJ3bnnigKeFGPQUCf/x0Smw4V8exogX/AOY3+/SgKxKxeU459KAgJOckntQJkkcgkGgAAFFz/XQEmJaY7jnk96BM9yPQelAf/wCX7UBv/jagGP8AKB6ZoDf00HMfO/0oAH5TQA/5moECSMDPFAvGASMjPP8AigVX+b60BW7/AHoHEJJD55oDd4snv70CsSjCcDmgVAAbgYoGYJ3nk9qBUAYHAoP/2Q==</binary></FictionBook>
diff --git a/tests/writer.html b/tests/writer.html
index b56e81292..4a60a7b97 100644
--- a/tests/writer.html
+++ b/tests/writer.html
@@ -35,7 +35,8 @@
<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>
+<p>There should be a hard line break<br />
+here.</p>
<hr />
<h1 id="block-quotes">Block Quotes</h1>
<p>E-mail style:</p>
@@ -419,13 +420,13 @@ Blah
<h1 id="latex">LaTeX</h1>
<ul>
<li></li>
-<li><span class="math">2 + 2 = 4</span></li>
-<li><span class="math"><em>x</em> ∈ <em>y</em></span></li>
-<li><span class="math"><em>α</em> ∧ <em>ω</em></span></li>
-<li><span class="math">223</span></li>
-<li><span class="math"><em>p</em></span>-Tree</li>
-<li>Here’s some display math: <br /><span class="math">$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</span><br /></li>
-<li>Here’s one that has a line break in it: <span class="math"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
+<li><span class="math inline">2 + 2 = 4</span></li>
+<li><span class="math inline"><em>x</em> ∈ <em>y</em></span></li>
+<li><span class="math inline"><em>α</em> ∧ <em>ω</em></span></li>
+<li><span class="math inline">223</span></li>
+<li><span class="math inline"><em>p</em></span>-Tree</li>
+<li>Here’s some display math: <br /><span class="math display">$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$</span><br /></li>
+<li>Here’s one that has a line break in it: <span class="math inline"><em>α</em> + <em>ω</em> × <em>x</em><sup>2</sup></span>.</li>
</ul>
<p>These shouldn’t be math:</p>
<ul>
@@ -480,7 +481,7 @@ Blah
<p><script type="text/javascript">
<!--
h='&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#46;&#110;&#x65;&#116;';a='&#64;';n='&#110;&#x6f;&#98;&#x6f;&#100;&#x79;';e=n+a+h;
-document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'" clas'+'s="em' + 'ail">'+'Email link'+'<\/'+'a'+'>');
+document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'" clas'+'s="em' + 'ail">'+'&#x45;&#x6d;&#x61;&#x69;&#108;&#32;&#108;&#x69;&#110;&#x6b;'+'<\/'+'a'+'>');
// -->
</script><noscript>&#x45;&#x6d;&#x61;&#x69;&#108;&#32;&#108;&#x69;&#110;&#x6b;&#32;&#40;&#110;&#x6f;&#98;&#x6f;&#100;&#x79;&#32;&#x61;&#116;&#32;&#110;&#x6f;&#x77;&#104;&#x65;&#114;&#x65;&#32;&#100;&#x6f;&#116;&#32;&#110;&#x65;&#116;&#x29;</noscript></p>
<p><a href="">Empty</a>.</p>
@@ -524,7 +525,8 @@ document.write('<a h'+'ref'+'="ma'+'ilto'+':'+e+'" clas'+'s="em' + 'ail">'+e+'<\
<h1 id="images">Images</h1>
<p>From “Voyage dans la Lune” by Georges Melies (1902):</p>
<div class="figure">
-<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" /><p class="caption">lalune</p>
+<img src="lalune.jpg" title="Voyage dans la Lune" alt="lalune" />
+<p class="caption">lalune</p>
</div>
<p>Here is a movie <img src="movie.jpg" alt="movie" /> icon.</p>
<hr />
diff --git a/tests/writer.icml b/tests/writer.icml
index 8922da7ed..b6f5b5e32 100644
--- a/tests/writer.icml
+++ b/tests/writer.icml
@@ -410,11 +410,6 @@
<Properties>
<BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
</Properties>
- </ParagraphStyle>
- <ParagraphStyle Self="ParagraphStyle/Rawblock" Name="Rawblock" LeftIndent="0">
- <Properties>
- <BasedOn type="object">$ID/NormalParagraphStyle</BasedOn>
- </Properties>
</ParagraphStyle>
</RootParagraphStyleGroup>
<RootTableStyleGroup Self="pandoc_table_styles">
@@ -1389,21 +1384,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Content>Interpreted markdown in a table:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;table&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;tr&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;td&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>This is </Content>
@@ -1412,16 +1392,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Content>emphasized</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;/td&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;td&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>And this is </Content>
@@ -1430,26 +1400,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Content>strong</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;/td&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;/tr&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;/table&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;script type=&quot;text/javascript&quot;&gt;document.write('This *should not* be interpreted as markdown');&lt;/script&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Here’s a simple block:</Content>
@@ -1497,31 +1447,11 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Content>This should just be an HTML comment:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;!-- Comment --&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Multiline:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;!--
-Blah
-Blah
---&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;!--
- This is another comment.
---&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Code block:</Content>
@@ -1537,11 +1467,6 @@ Blah
<Content>Just plain comment, with trailing spaces on the line:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;!-- foo --&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Code:</Content>
@@ -1557,51 +1482,6 @@ Blah
<Content>Hr’s:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot; /&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>&lt;hr class=&quot;foo&quot; id=&quot;bar&quot;&gt;</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Inline Markup</Content>
@@ -1980,9 +1860,7 @@ Blah
</CharacterStyleRange><Br />
</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList &gt; first" NumberingContinue="false">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>\cite[22-23]{smith.1899}</Content>
- </CharacterStyleRange><Br />
+ <Br />
</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
@@ -2097,15 +1975,6 @@ Blah
<Content>Here’s a LaTeX table:</Content>
</CharacterStyleRange><Br />
</ParagraphStyleRange>
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Rawblock">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>\begin{tabular}{|l|l|}\hline
-Animal &amp; Number \\ \hline
-Dog &amp; 2 \\
-Cat &amp; 1 \\ \hline
-\end{tabular}</Content>
- </CharacterStyleRange><Br />
-</ParagraphStyleRange>
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Header1">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Special Characters</Content>
@@ -2645,7 +2514,7 @@ Cat &amp; 1 \\ \hline
<GraphicBounds Left="0" Top="0" Right="150" Bottom="100" />
</Profile>
</Properties>
- <Link Self="ueb" LinkResourceURI="lalune.jpg" />
+ <Link Self="ueb" LinkResourceURI="file:lalune.jpg" />
</Image>
</Rectangle>
</CharacterStyleRange><Br />
@@ -2675,7 +2544,7 @@ Cat &amp; 1 \\ \hline
<GraphicBounds Left="0" Top="0" Right="150" Bottom="100" />
</Profile>
</Properties>
- <Link Self="ueb" LinkResourceURI="movie.jpg" />
+ <Link Self="ueb" LinkResourceURI="file:movie.jpg" />
</Image>
</Rectangle>
</CharacterStyleRange>
@@ -2848,39 +2717,39 @@ Cat &amp; 1 \\ \hline
</ParagraphStyleRange>
</Story>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://google.com" Name="link" DestinationURL="http://google.com" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//google.com" Name="link" DestinationURL="http://google.com" DestinationUniqueKey="1" />
<Hyperlink Self="uf-31" Name="http://google.com" Source="htss-31" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://google.com</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//google.com</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
<Hyperlink Self="uf-30" Name="http://example.com/" Source="htss-30" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://example.com/</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto:nobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
<Hyperlink Self="uf-29" Name="mailto:nobody@nowhere.net" Source="htss-29" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/mailto:nobody@nowhere.net</Destination>
+ <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/" Name="link" DestinationURL="http://example.com/" DestinationUniqueKey="1" />
<Hyperlink Self="uf-28" Name="http://example.com/" Source="htss-28" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://example.com/</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
<Hyperlink Self="uf-27" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-27" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//script?foo=1&amp;bar=2" Name="link" DestinationURL="/script?foo=1&amp;bar=2" DestinationUniqueKey="1" />
@@ -2897,18 +2766,18 @@ Cat &amp; 1 \\ \hline
<Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://att.com/" Name="link" DestinationURL="http://att.com/" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//att.com/" Name="link" DestinationURL="http://att.com/" DestinationUniqueKey="1" />
<Hyperlink Self="uf-24" Name="http://att.com/" Source="htss-24" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://att.com/</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//att.com/</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
<Hyperlink Self="uf-23" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-23" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
@@ -2988,11 +2857,11 @@ Cat &amp; 1 \\ \hline
<Destination type="object">HyperlinkURLDestination/</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto:nobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/mailto%3anobody@nowhere.net" Name="link" DestinationURL="mailto:nobody@nowhere.net" DestinationUniqueKey="1" />
<Hyperlink Self="uf-11" Name="mailto:nobody@nowhere.net" Source="htss-11" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/mailto:nobody@nowhere.net</Destination>
+ <Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url/with_underscore" Name="link" DestinationURL="/url/with_underscore" DestinationUniqueKey="1" />
@@ -3044,11 +2913,11 @@ Cat &amp; 1 \\ \hline
<Destination type="object">HyperlinkURLDestination//url/</Destination>
</Properties>
</Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
+ <HyperlinkURLDestination Self="HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2" Name="link" DestinationURL="http://example.com/?foo=1&amp;bar=2" DestinationUniqueKey="1" />
<Hyperlink Self="uf-3" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-3" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination/http://example.com/?foo=1&amp;bar=2</Destination>
+ <Destination type="object">HyperlinkURLDestination/http%3a//example.com/?foo=1&amp;bar=2</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
diff --git a/tests/writer.latex b/tests/writer.latex
index a966e374b..8b34777fa 100644
--- a/tests/writer.latex
+++ b/tests/writer.latex
@@ -23,17 +23,6 @@
\usepackage{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
-\usepackage{fancyvrb}
-\VerbatimFootnotes
-\usepackage{graphicx}
-\makeatletter
-\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
-\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
-\makeatother
-% Scale images if necessary, so that they will not overflow the page
-% margins by default, and it is still possible to overwrite the defaults
-% using explicit options in \includegraphics[width, height, ...]{}
-\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
\ifxetex
\usepackage[setpagesize=false, % page size defined by xetex
unicode=false, % unicode breaks when used with xetex
@@ -41,6 +30,7 @@
\else
\usepackage[unicode=true]{hyperref}
\fi
+\usepackage[usenames,dvipsnames]{color}
\hypersetup{breaklinks=true,
bookmarks=true,
pdfauthor={John MacFarlane; Anonymous},
@@ -51,12 +41,25 @@
linkcolor=magenta,
pdfborder={0 0 0}}
\urlstyle{same} % don't use monospace font for urls
+\usepackage{fancyvrb}
+\VerbatimFootnotes
+\usepackage{graphicx,grffile}
+\makeatletter
+\def\maxwidth{\ifdim\Gin@nat@width>\linewidth\linewidth\else\Gin@nat@width\fi}
+\def\maxheight{\ifdim\Gin@nat@height>\textheight\textheight\else\Gin@nat@height\fi}
+\makeatother
+% Scale images if necessary, so that they will not overflow the page
+% margins by default, and it is still possible to overwrite the defaults
+% using explicit options in \includegraphics[width, height, ...]{}
+\setkeys{Gin}{width=\maxwidth,height=\maxheight,keepaspectratio}
\usepackage[normalem]{ulem}
% avoid problems with \sout in headers with hyperref:
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
\setlength{\parindent}{0pt}
\setlength{\parskip}{6pt plus 2pt minus 1pt}
\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
\setcounter{secnumdepth}{0}
\VerbatimFootnotes % allows verbatim text in footnotes
@@ -64,6 +67,16 @@
\author{John MacFarlane \and Anonymous}
\date{July 17, 2006}
+% Redefines (sub)paragraphs to behave more like sections
+\ifx\paragraph\undefined\else
+\let\oldparagraph\paragraph
+\renewcommand{\paragraph}[1]{\oldparagraph{#1}\mbox{}}
+\fi
+\ifx\subparagraph\undefined\else
+\let\oldsubparagraph\subparagraph
+\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
+\fi
+
\begin{document}
\maketitle
@@ -74,10 +87,11 @@ markdown test suite.
\section{Headers}\label{headers}
-\subsection{Level 2 with an \href{/url}{embedded
-link}}\label{level-2-with-an-embedded-link}
+\subsection{\texorpdfstring{Level 2 with an \href{/url}{embedded
+link}}{Level 2 with an embedded link}}\label{level-2-with-an-embedded-link}
-\subsubsection{Level 3 with \emph{emphasis}}\label{level-3-with-emphasis}
+\subsubsection{\texorpdfstring{Level 3 with
+\emph{emphasis}}{Level 3 with emphasis}}\label{level-3-with-emphasis}
\paragraph{Level 4}\label{level-4}
@@ -85,7 +99,8 @@ link}}\label{level-2-with-an-embedded-link}
\section{Level 1}\label{level-1}
-\subsection{Level 2 with \emph{emphasis}}\label{level-2-with-emphasis}
+\subsection{\texorpdfstring{Level 2 with
+\emph{emphasis}}{Level 2 with emphasis}}\label{level-2-with-emphasis}
\subsubsection{Level 3}\label{level-3}
@@ -107,7 +122,8 @@ item.
Here's one with a bullet. * criminey.
-There should be a hard line break\\here.
+There should be a hard line break\\
+here.
\begin{center}\rule{0.5\linewidth}{\linethickness}\end{center}
@@ -132,7 +148,7 @@ A list:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
item one
\item
@@ -187,7 +203,7 @@ These should not be escaped: \$ \\ \> \[ \{
Asterisks tight:
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
asterisk 1
\item
@@ -210,7 +226,7 @@ Asterisks loose:
Pluses tight:
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
Plus 1
\item
@@ -233,7 +249,7 @@ Pluses loose:
Minuses tight:
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
Minus 1
\item
@@ -259,7 +275,7 @@ Tight:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
First
\item
@@ -272,7 +288,7 @@ and:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
One
\item
@@ -322,17 +338,17 @@ Multiple paragraphs:
\subsection{Nested}\label{nested}
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
Tab
\begin{itemize}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Tab
\begin{itemize}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Tab
\end{itemize}
@@ -343,14 +359,14 @@ Here's another:
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
First
\item
Second:
\begin{itemize}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Fee
\item
@@ -372,7 +388,7 @@ Same thing but with paragraphs:
Second:
\begin{itemize}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Fee
\item
@@ -415,7 +431,7 @@ Same thing but with paragraphs:
\begin{enumerate}
\def\labelenumii{\roman{enumii}.}
\setcounter{enumii}{3}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
sublist with roman numerals, starting with 4
\item
@@ -423,7 +439,7 @@ Same thing but with paragraphs:
\begin{enumerate}
\def\labelenumiii{(\Alph{enumiii})}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
a subsublist
\item
@@ -436,27 +452,27 @@ Nesting:
\begin{enumerate}
\def\labelenumi{\Alph{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
Upper Alpha
\begin{enumerate}
\def\labelenumii{\Roman{enumii}.}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Upper Roman.
\begin{enumerate}
\def\labelenumiii{(\arabic{enumiii})}
\setcounter{enumiii}{5}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Decimal start with 6
\begin{enumerate}
\def\labelenumiv{\alph{enumiv})}
\setcounter{enumiv}{2}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Lower alpha with paren
\end{enumerate}
@@ -467,14 +483,14 @@ Nesting:
Autonumbering:
\begin{enumerate}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
Autonumber.
\item
More.
\begin{enumerate}
- \itemsep1pt\parskip0pt\parsep0pt
+ \tightlist
\item
Nested.
\end{enumerate}
@@ -493,7 +509,7 @@ B. Williams
Tight using spaces:
\begin{description}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item[apple]
red fruit
\item[orange]
@@ -505,7 +521,7 @@ yellow fruit
Tight using tabs:
\begin{description}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item[apple]
red fruit
\item[orange]
@@ -547,7 +563,7 @@ orange block quote
Multiple definitions, tight:
\begin{description}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item[apple]
red fruit
@@ -583,7 +599,7 @@ orange fruit
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
sublist
\item
@@ -709,7 +725,7 @@ Ellipses\ldots{}and\ldots{}and\ldots{}.
\section{LaTeX}\label{latex}
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
\cite[22-23]{smith.1899}
\item
@@ -732,9 +748,9 @@ Ellipses\ldots{}and\ldots{}and\ldots{}.
These shouldn't be math:
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
- To get the famous equation, write \texttt{\$e = mc\^{}2\$}.
+ To get the famous equation, write \texttt{\$e\ =\ mc\^{}2\$}.
\item
\$22,000 is a \emph{lot} of money. So is \$34,000. (It worked if ``lot'' is
emphasized.)
@@ -759,7 +775,7 @@ Cat & 1 \\ \hline
Here is some unicode:
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
I hat: Î
\item
@@ -883,7 +899,7 @@ Here's an \href{/script?foo=1\&bar=2}{inline link in pointy braces}.
With an ampersand: \url{http://example.com/?foo=1\&bar=2}
\begin{itemize}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
In a list?
\item
@@ -949,7 +965,7 @@ Notes can go in quotes.\footnote{In quote.}
\begin{enumerate}
\def\labelenumi{\arabic{enumi}.}
-\itemsep1pt\parskip0pt\parsep0pt
+\tightlist
\item
And in list items.\footnote{In list.}
\end{enumerate}
diff --git a/tests/writer.markdown b/tests/writer.markdown
index ad97b15ef..6a0b9801c 100644
--- a/tests/writer.markdown
+++ b/tests/writer.markdown
@@ -80,7 +80,7 @@ E-mail style:
>
> > nested
-This should not be a block quote: 2 \> 1.
+This should not be a block quote: 2 &gt; 1.
And a following paragraph.
@@ -549,8 +549,8 @@ LaTeX
These shouldn’t be math:
- To get the famous equation, write `$e = mc^2$`.
-- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is
- emphasized.)
+- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot”
+ is emphasized.)
- Shoes (\$20) and socks (\$5).
- Escaped `$`: \$73 *this should be emphasized* 23\$.
@@ -581,9 +581,9 @@ AT&T is another way to write it.
This & that.
-4 \< 5.
+4 &lt; 5.
-6 \> 5.
+6 &gt; 5.
Backslash: \\
@@ -597,15 +597,15 @@ Left brace: {
Right brace: }
-Left bracket: [
+Left bracket: \[
-Right bracket: ]
+Right bracket: \]
Left paren: (
Right paren: )
-Greater-than: \>
+Greater-than: &gt;
Hash: \#
@@ -652,7 +652,7 @@ Foo [bar](/url/).
Foo [bar](/url/).
-With [embedded [brackets]](/url/).
+With [embedded \[brackets\]](/url/).
[b](/url/) by itself should be a link.
@@ -662,7 +662,7 @@ Indented [twice](/url).
Indented [thrice](/url).
-This should [not][] be a link.
+This should \[not\]\[\] be a link.
[not]: /url
@@ -716,8 +716,8 @@ Footnotes
=========
Here is a footnote reference,[^1] and another.[^2] This should *not* be a
-footnote reference, because it contains a space.[\^my note] Here is an inline
-note.[^3]
+footnote reference, because it contains a space.\[\^my note\] Here is an
+inline note.[^3]
> Notes can go in quotes.[^4]
@@ -740,7 +740,7 @@ This paragraph should not be part of the note, as it is not indented.
[^3]: This is *easier* to type. Inline notes may contain
[links](http://google.com) and `]` verbatim characters, as well as
- [bracketed text].
+ \[bracketed text\].
[^4]: In quote.
diff --git a/tests/writer.mediawiki b/tests/writer.mediawiki
index efd43cb04..066606c00 100644
--- a/tests/writer.mediawiki
+++ b/tests/writer.mediawiki
@@ -36,7 +36,8 @@ In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Beca
Here’s one with a bullet. * criminey.
-There should be a hard line break<br />here.
+There should be a hard line break<br />
+here.
-----
@@ -623,9 +624,9 @@ Auto-links should not occur here: <code>&lt;http://example.com/&gt;</code>
From “Voyage dans la Lune” by Georges Melies (1902):
-[[Image:lalune.jpg|frame|none|alt=Voyage dans la Lune|caption lalune]]
+[[File:lalune.jpg|frame|none|alt=Voyage dans la Lune|caption lalune]]
-Here is a movie [[Image:movie.jpg|movie]] icon.
+Here is a movie [[File:movie.jpg|movie]] icon.
-----
diff --git a/tests/writer.opendocument b/tests/writer.opendocument
index 81c793a62..5007c5635 100644
--- a/tests/writer.opendocument
+++ b/tests/writer.opendocument
@@ -864,7 +864,7 @@
</office:automatic-styles>
<office:body>
<office:text>
-<text:h text:style-name="Title">Pandoc Test Suite</text:h>
+<text:p text:style-name="Title">Pandoc Test Suite</text:p>
<text:p text:style-name="Author">John MacFarlane</text:p>
<text:p text:style-name="Author">Anonymous</text:p>
<text:p text:style-name="Date">July 17, 2006</text:p>
@@ -1576,7 +1576,8 @@ link in pointy braces</text:span></text:a>.</text:p>
<text:h text:style-name="Heading_20_1" text:outline-level="1">Images</text:h>
<text:p text:style-name="First_20_paragraph">From “Voyage dans la Lune” by
Georges Melies (1902):</text:p>
-<text:p text:style-name="Text_20_body"><draw:frame draw:name="img1"><draw:image xlink:href="lalune.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame></text:p>
+<text:p text:style-name="FigureWithCaption"><draw:frame draw:name="img1"><draw:image xlink:href="lalune.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame></text:p>
+<text:p text:style-name="FigureCaption">lalune</text:p>
<text:p text:style-name="Text_20_body">Here is a movie
<draw:frame draw:name="img2"><draw:image xlink:href="movie.jpg" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad" /></draw:frame>
icon.</text:p>
diff --git a/tests/writer.opml b/tests/writer.opml
index 54be4b671..c10ca44c8 100644
--- a/tests/writer.opml
+++ b/tests/writer.opml
@@ -18,7 +18,7 @@
</outline>
<outline text="Level 1">
<outline text="Level 2 with &lt;em&gt;emphasis&lt;/em&gt;">
- <outline text="Level 3" _note="with no blank line&#10;">
+ <outline text="Level 3" _note="with no blank line">
</outline>
</outline>
<outline text="Level 2" _note="with no blank line&#10;&#10;------------------------------------------------------------------------">
@@ -26,14 +26,14 @@
</outline>
<outline text="Paragraphs" _note="Here’s a regular paragraph.&#10;&#10;In Markdown 1.0.0 and earlier. Version 8. This line turns into a list&#10;item. Because a hard-wrapped line in the middle of a paragraph looked&#10;like a list item.&#10;&#10;Here’s one with a bullet. \* criminey.&#10;&#10;There should be a hard line break\&#10;here.&#10;&#10;------------------------------------------------------------------------">
</outline>
-<outline text="Block Quotes" _note="E-mail style:&#10;&#10;&gt; This is a block quote. It is pretty short.&#10;&#10;&gt; Code in a block quote:&#10;&gt;&#10;&gt; sub status {&#10;&gt; print &quot;working&quot;;&#10;&gt; }&#10;&gt;&#10;&gt; A list:&#10;&gt;&#10;&gt; 1. item one&#10;&gt; 2. item two&#10;&gt;&#10;&gt; Nested block quotes:&#10;&gt;&#10;&gt; &gt; nested&#10;&gt;&#10;&gt; &gt; nested&#10;&#10;This should not be a block quote: 2 \&gt; 1.&#10;&#10;And a following paragraph.&#10;&#10;------------------------------------------------------------------------">
+<outline text="Block Quotes" _note="E-mail style:&#10;&#10;&gt; This is a block quote. It is pretty short.&#10;&#10;&gt; Code in a block quote:&#10;&gt;&#10;&gt; sub status {&#10;&gt; print &quot;working&quot;;&#10;&gt; }&#10;&gt;&#10;&gt; A list:&#10;&gt;&#10;&gt; 1. item one&#10;&gt; 2. item two&#10;&gt;&#10;&gt; Nested block quotes:&#10;&gt;&#10;&gt; &gt; nested&#10;&gt;&#10;&gt; &gt; nested&#10;&#10;This should not be a block quote: 2 &amp;gt; 1.&#10;&#10;And a following paragraph.&#10;&#10;------------------------------------------------------------------------">
</outline>
<outline text="Code Blocks" _note="Code:&#10;&#10; ---- (should be four hyphens)&#10;&#10; sub status {&#10; print &quot;working&quot;;&#10; }&#10;&#10; this code block is indented by one tab&#10;&#10;And:&#10;&#10; this code block is indented by two tabs&#10;&#10; These should not be escaped: \$ \\ \&gt; \[ \{&#10;&#10;------------------------------------------------------------------------">
</outline>
<outline text="Lists">
<outline text="Unordered" _note="Asterisks tight:&#10;&#10;- asterisk 1&#10;- asterisk 2&#10;- asterisk 3&#10;&#10;Asterisks loose:&#10;&#10;- asterisk 1&#10;&#10;- asterisk 2&#10;&#10;- asterisk 3&#10;&#10;Pluses tight:&#10;&#10;- Plus 1&#10;- Plus 2&#10;- Plus 3&#10;&#10;Pluses loose:&#10;&#10;- Plus 1&#10;&#10;- Plus 2&#10;&#10;- Plus 3&#10;&#10;Minuses tight:&#10;&#10;- Minus 1&#10;- Minus 2&#10;- Minus 3&#10;&#10;Minuses loose:&#10;&#10;- Minus 1&#10;&#10;- Minus 2&#10;&#10;- Minus 3&#10;&#10;">
</outline>
- <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy dog’s&#10; back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.&#10;&#10;">
+ <outline text="Ordered" _note="Tight:&#10;&#10;1. First&#10;2. Second&#10;3. Third&#10;&#10;and:&#10;&#10;1. One&#10;2. Two&#10;3. Three&#10;&#10;Loose using tabs:&#10;&#10;1. First&#10;&#10;2. Second&#10;&#10;3. Third&#10;&#10;and using spaces:&#10;&#10;1. One&#10;&#10;2. Two&#10;&#10;3. Three&#10;&#10;Multiple paragraphs:&#10;&#10;1. Item 1, graf one.&#10;&#10; Item 1. graf two. The quick brown fox jumped over the lazy&#10; dog’s back.&#10;&#10;2. Item 2.&#10;&#10;3. Item 3.&#10;&#10;">
</outline>
<outline text="Nested" _note="- Tab&#10; - Tab&#10; - Tab&#10;&#10;Here’s another:&#10;&#10;1. First&#10;2. Second:&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third&#10;&#10;Same thing but with paragraphs:&#10;&#10;1. First&#10;&#10;2. Second:&#10;&#10; - Fee&#10; - Fie&#10; - Foe&#10;&#10;3. Third&#10;&#10;">
</outline>
@@ -50,23 +50,23 @@
</outline>
<outline text="Smart quotes, ellipses, dashes" _note="“Hello,” said the spider. “‘Shelob’ is my name.”&#10;&#10;‘A’, ‘B’, and ‘C’ are letters.&#10;&#10;‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. So is ‘pine.’&#10;&#10;‘He said, “I want to go.”’ Were you alive in the 70’s?&#10;&#10;Here is some quoted ‘`code`’ and a “[quoted&#10;link](http://example.com/?foo=1&amp;bar=2)”.&#10;&#10;Some dashes: one—two — three—four — five.&#10;&#10;Dashes between numbers: 5–7, 255–66, 1987–1999.&#10;&#10;Ellipses…and…and….&#10;&#10;------------------------------------------------------------------------">
</outline>
-<outline text="LaTeX" _note="- \cite[22-23]{smith.1899}&#10;- $2+2=4$&#10;- $x \in y$&#10;- $\alpha \wedge \omega$&#10;- $223$&#10;- $p$-Tree&#10;- Here’s some display math:&#10; $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it:&#10; $\alpha + \omega \times x^2$.&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot” is&#10; emphasized.)&#10;- Shoes (\$20) and socks (\$5).&#10;- Escaped `$`: \$73 *this should be emphasized* 23\$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;\begin{tabular}{|l|l|}\hline&#10;Animal &amp; Number \\ \hline&#10;Dog &amp; 2 \\&#10;Cat &amp; 1 \\ \hline&#10;\end{tabular}&#10;&#10;------------------------------------------------------------------------">
+<outline text="LaTeX" _note="- \cite[22-23]{smith.1899}&#10;- $2+2=4$&#10;- $x \in y$&#10;- $\alpha \wedge \omega$&#10;- $223$&#10;- $p$-Tree&#10;- Here’s some display math:&#10; $$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$&#10;- Here’s one that has a line break in it:&#10; $\alpha + \omega \times x^2$.&#10;&#10;These shouldn’t be math:&#10;&#10;- To get the famous equation, write `$e = mc^2$`.&#10;- \$22,000 is a *lot* of money. So is \$34,000. (It worked if “lot”&#10; is emphasized.)&#10;- Shoes (\$20) and socks (\$5).&#10;- Escaped `$`: \$73 *this should be emphasized* 23\$.&#10;&#10;Here’s a LaTeX table:&#10;&#10;\begin{tabular}{|l|l|}\hline&#10;Animal &amp; Number \\ \hline&#10;Dog &amp; 2 \\&#10;Cat &amp; 1 \\ \hline&#10;\end{tabular}&#10;&#10;------------------------------------------------------------------------">
</outline>
-<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 \&lt; 5.&#10;&#10;6 \&gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: [&#10;&#10;Right bracket: ]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: \&gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
+<outline text="Special Characters" _note="Here is some unicode:&#10;&#10;- I hat: Î&#10;- o umlaut: ö&#10;- section: §&#10;- set membership: ∈&#10;- copyright: ©&#10;&#10;AT&amp;T has an ampersand in their name.&#10;&#10;AT&amp;T is another way to write it.&#10;&#10;This &amp; that.&#10;&#10;4 &amp;lt; 5.&#10;&#10;6 &amp;gt; 5.&#10;&#10;Backslash: \\&#10;&#10;Backtick: \`&#10;&#10;Asterisk: \*&#10;&#10;Underscore: \_&#10;&#10;Left brace: {&#10;&#10;Right brace: }&#10;&#10;Left bracket: \[&#10;&#10;Right bracket: \]&#10;&#10;Left paren: (&#10;&#10;Right paren: )&#10;&#10;Greater-than: &amp;gt;&#10;&#10;Hash: \#&#10;&#10;Period: .&#10;&#10;Bang: !&#10;&#10;Plus: +&#10;&#10;Minus: -&#10;&#10;------------------------------------------------------------------------">
</outline>
<outline text="Links">
- <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().&#10;">
+ <outline text="Explicit" _note="Just a [URL](/url/).&#10;&#10;[URL and title](/url/ &quot;title&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by two spaces&quot;).&#10;&#10;[URL and title](/url/ &quot;title preceded by a tab&quot;).&#10;&#10;[URL and title](/url/ &quot;title with &quot;quotes&quot; in it&quot;)&#10;&#10;[URL and title](/url/ &quot;title with single quotes&quot;)&#10;&#10;[with\_underscore](/url/with_underscore)&#10;&#10;[Email link](mailto:nobody@nowhere.net)&#10;&#10;[Empty]().">
</outline>
- <outline text="Reference" _note="Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;With [embedded [brackets]](/url/).&#10;&#10;[b](/url/) by itself should be a link.&#10;&#10;Indented [once](/url).&#10;&#10;Indented [twice](/url).&#10;&#10;Indented [thrice](/url).&#10;&#10;This should [not][] be a link.&#10;&#10; [not]: /url&#10;&#10;Foo [bar](/url/ &quot;Title with &quot;quotes&quot; inside&quot;).&#10;&#10;Foo [biz](/url/ &quot;Title with &quot;quote&quot; inside&quot;).&#10;">
+ <outline text="Reference" _note="Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;Foo [bar](/url/).&#10;&#10;With [embedded \[brackets\]](/url/).&#10;&#10;[b](/url/) by itself should be a link.&#10;&#10;Indented [once](/url).&#10;&#10;Indented [twice](/url).&#10;&#10;Indented [thrice](/url).&#10;&#10;This should \[not\]\[\] be a link.&#10;&#10; [not]: /url&#10;&#10;Foo [bar](/url/ &quot;Title with &quot;quotes&quot; inside&quot;).&#10;&#10;Foo [biz](/url/ &quot;Title with &quot;quote&quot; inside&quot;).">
</outline>
- <outline text="With ampersands" _note="Here’s a [link with an ampersand in the&#10;URL](http://example.com/?foo=1&amp;bar=2).&#10;&#10;Here’s a link with an amersand in the link text:&#10;[AT&amp;T](http://att.com/ &quot;AT&amp;T&quot;).&#10;&#10;Here’s an [inline link](/script?foo=1&amp;bar=2).&#10;&#10;Here’s an [inline link in pointy braces](/script?foo=1&amp;bar=2).&#10;">
+ <outline text="With ampersands" _note="Here’s a [link with an ampersand in the&#10;URL](http://example.com/?foo=1&amp;bar=2).&#10;&#10;Here’s a link with an amersand in the link text:&#10;[AT&amp;T](http://att.com/ &quot;AT&amp;T&quot;).&#10;&#10;Here’s an [inline link](/script?foo=1&amp;bar=2).&#10;&#10;Here’s an [inline link in pointy braces](/script?foo=1&amp;bar=2).">
</outline>
<outline text="Autolinks" _note="With an ampersand: &lt;http://example.com/?foo=1&amp;bar=2&gt;&#10;&#10;- In a list?&#10;- &lt;http://example.com/&gt;&#10;- It should.&#10;&#10;An e-mail address: &lt;nobody@nowhere.net&gt;&#10;&#10;&gt; Blockquoted: &lt;http://example.com/&gt;&#10;&#10;Auto-links should not occur here: `&lt;http://example.com/&gt;`&#10;&#10; or here: &lt;http://example.com/&gt;&#10;&#10;------------------------------------------------------------------------">
</outline>
</outline>
<outline text="Images" _note="From “Voyage dans la Lune” by Georges Melies (1902):&#10;&#10;![lalune](lalune.jpg &quot;Voyage dans la Lune&quot;)&#10;&#10;Here is a movie ![movie](movie.jpg) icon.&#10;&#10;------------------------------------------------------------------------">
</outline>
-<outline text="Footnotes" _note="Here is a footnote reference,[^1] and another.[^2] This should *not* be&#10;a footnote reference, because it contains a space.[\^my note] Here is an&#10;inline note.[^3]&#10;&#10;&gt; Notes can go in quotes.[^4]&#10;&#10;1. And in list items.[^5]&#10;&#10;This paragraph should not be part of the note, as it is not indented.&#10;&#10;[^1]: Here is the footnote. It can go anywhere after the footnote&#10; reference. It need not be placed at the end of the document.&#10;&#10;[^2]: Here’s the long note. This one contains multiple blocks.&#10;&#10; Subsequent blocks are indented to show that they belong to the&#10; footnote (as with list items).&#10;&#10; { &lt;code&gt; }&#10;&#10; If you want, you can indent every line, but you can also be lazy and&#10; just indent the first line of each block.&#10;&#10;[^3]: This is *easier* to type. Inline notes may contain&#10; [links](http://google.com) and `]` verbatim characters, as well as&#10; [bracketed text].&#10;&#10;[^4]: In quote.&#10;&#10;[^5]: In list.&#10;">
+<outline text="Footnotes" _note="Here is a footnote reference,[^1] and another.[^2] This should *not* be&#10;a footnote reference, because it contains a space.\[\^my note\] Here is&#10;an inline note.[^3]&#10;&#10;&gt; Notes can go in quotes.[^4]&#10;&#10;1. And in list items.[^5]&#10;&#10;This paragraph should not be part of the note, as it is not indented.&#10;&#10;[^1]: Here is the footnote. It can go anywhere after the footnote&#10; reference. It need not be placed at the end of the document.&#10;&#10;[^2]: Here’s the long note. This one contains multiple blocks.&#10;&#10; Subsequent blocks are indented to show that they belong to the&#10; footnote (as with list items).&#10;&#10; { &lt;code&gt; }&#10;&#10; If you want, you can indent every line, but you can also be lazy and&#10; just indent the first line of each block.&#10;&#10;[^3]: This is *easier* to type. Inline notes may contain&#10; [links](http://google.com) and `]` verbatim characters, as well as&#10; \[bracketed text\].&#10;&#10;[^4]: In quote.&#10;&#10;[^5]: In list.">
</outline>
</body>
</opml>
diff --git a/tests/writer.plain b/tests/writer.plain
index fab0489ac..ba476f21d 100644
--- a/tests/writer.plain
+++ b/tests/writer.plain
@@ -449,9 +449,9 @@ This is code: >, $, \, \$, <html>.
~~This is _strikeout_.~~
-Superscripts: a^bc^d a^_hello_^ a^hello there^.
+Superscripts: abcd a_hello_ ahello there.
-Subscripts: H~2~O, H~23~O, H~many of them~O.
+Subscripts: H2O, H23O, Hmany of themO.
These should not be superscripts or subscripts, because of the unescaped
spaces: a^b c^d, a~b c~d.
@@ -494,13 +494,13 @@ LATEX
- p-Tree
- Here’s some display math:
$$\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}$$
-- Here’s one that has a line break in it: α + ω × x^2^.
+- Here’s one that has a line break in it: α + ω × x2.
These shouldn’t be math:
- To get the famous equation, write $e = mc^2$.
-- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot” is
- emphasized.)
+- $22,000 is a _lot_ of money. So is $34,000. (It worked if “lot”
+ is emphasized.)
- Shoes ($20) and socks ($5).
- Escaped $: $73 _this should be emphasized_ 23$.
diff --git a/tests/writer.rst b/tests/writer.rst
index 1a998d2ae..1aeeacacb 100644
--- a/tests/writer.rst
+++ b/tests/writer.rst
@@ -10,6 +10,10 @@ Pandoc Test Suite
:format: html latex
..
+.. role:: raw-latex(raw)
+ :format: latex
+..
+
This is a set of tests for pandoc. Most of them are adapted from John Gruber’s
markdown test suite.
@@ -657,7 +661,7 @@ Ellipses…and…and….
LaTeX
=====
--
+- :raw-latex:`\cite[22-23]{smith.1899}`
- :math:`2+2=4`
- :math:`x \in y`
- :math:`\alpha \wedge \omega`
@@ -839,6 +843,7 @@ From “Voyage dans la Lune” by Georges Melies (1902):
:alt: Voyage dans la Lune
lalune
+
Here is a movie |movie| icon.
--------------
diff --git a/tests/writer.texinfo b/tests/writer.texinfo
index 7b59ea651..ca87da1a9 100644
--- a/tests/writer.texinfo
+++ b/tests/writer.texinfo
@@ -36,7 +36,8 @@ July 17, 2006
@node Top
@top Pandoc Test Suite
-This is a set of tests for pandoc. Most of them are adapted from John Gruber's markdown test suite.
+This is a set of tests for pandoc. Most of them are adapted from John Gruber's
+markdown test suite.
@iftex
@bigskip@hrule@bigskip
@@ -125,11 +126,14 @@ with no blank line
@anchor{#paragraphs}
Here's a regular paragraph.
-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.
+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.
Here's one with a bullet. * criminey.
-There should be a hard line break@*here.
+There should be a hard line break@*
+here.
@iftex
@bigskip@hrule@bigskip
@@ -734,11 +738,14 @@ This is code: @code{>}, @code{$}, @code{\}, @code{\$}, @code{<html>}.
@textstrikeout{This is @emph{strikeout}.}
-Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}} a@textsuperscript{hello@ there}.
+Superscripts: a@textsuperscript{bc}d a@textsuperscript{@emph{hello}}
+a@textsuperscript{hello@ there}.
-Subscripts: H@textsubscript{2}O, H@textsubscript{23}O, H@textsubscript{many@ of@ them}O.
+Subscripts: H@textsubscript{2}O, H@textsubscript{23}O,
+H@textsubscript{many@ of@ them}O.
-These should not be superscripts or subscripts, because of the unescaped spaces: a^b c^d, a~b c~d.
+These should not be superscripts or subscripts, because of the unescaped
+spaces: a^b c^d, a~b c~d.
@iftex
@bigskip@hrule@bigskip
@@ -758,7 +765,8 @@ These should not be superscripts or subscripts, because of the unescaped spaces:
`He said, ``I want to go.''' Were you alive in the 70's?
-Here is some quoted `@code{code}' and a ``@uref{http://example.com/?foo=1&bar=2,quoted link}''.
+Here is some quoted `@code{code}' and a
+``@uref{http://example.com/?foo=1&bar=2,quoted link}''.
Some dashes: one---two --- three---four --- five.
@@ -792,7 +800,8 @@ Ellipses@dots{}and@dots{}and@dots{}.
@item
@math{p}-Tree
@item
-Here's some display math: @math{\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}}
+Here's some display math:
+@math{\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}}
@item
Here's one that has a line break in it: @math{\alpha + \omega \times x^2}.
@end itemize
@@ -803,7 +812,8 @@ These shouldn't be math:
@item
To get the famous equation, write @code{$e = mc^2$}.
@item
-$22,000 is a @emph{lot} of money. So is $34,000. (It worked if ``lot'' is emphasized.)
+$22,000 is a @emph{lot} of money. So is $34,000. (It worked if ``lot'' is
+emphasized.)
@item
Shoes ($20) and socks ($5).
@item
@@ -956,7 +966,8 @@ Foo @uref{/url/,biz}.
@node With ampersands
@section With ampersands
@anchor{#with-ampersands}
-Here's a @uref{http://example.com/?foo=1&bar=2,link with an ampersand in the URL}.
+Here's a @uref{http://example.com/?foo=1&bar=2,link with an ampersand in the
+URL}.
Here's a link with an amersand in the link text: @uref{http://att.com/,AT&T}.
@@ -1018,15 +1029,24 @@ Here is a movie @image{movie,,,movie,jpg} icon.
@node Footnotes
@chapter Footnotes
@anchor{#footnotes}
-Here is a footnote reference,@footnote{Here is the footnote. It can go anywhere after the footnote reference. It need not be placed at the end of the document.} and another.@footnote{Here's the long note. This one contains multiple blocks.
+Here is a footnote reference,@footnote{Here is the footnote. It can go
+anywhere after the footnote reference. It need not be placed at the end of the
+document.} and another.@footnote{Here's the long note. This one contains
+multiple blocks.
-Subsequent blocks are indented to show that they belong to the footnote (as with list items).
+Subsequent blocks are indented to show that they belong to the footnote (as
+with list items).
@verbatim
{ <code> }
@end verbatim
-If you want, you can indent every line, but you can also be lazy and just indent the first line of each block.} This should @emph{not} be a footnote reference, because it contains a space.[^my note] Here is an inline note.@footnote{This is @emph{easier} to type. Inline notes may contain @uref{http://google.com,links} and @code{]} verbatim characters, as well as [bracketed text].}
+If you want, you can indent every line, but you can also be lazy and just
+indent the first line of each block.} This should @emph{not} be a footnote
+reference, because it contains a space.[^my note] Here is an inline
+note.@footnote{This is @emph{easier} to type. Inline notes may contain
+@uref{http://google.com,links} and @code{]} verbatim characters, as well as
+[bracketed text].}
@quotation
Notes can go in quotes.@footnote{In quote.}
diff --git a/tests/writer.textile b/tests/writer.textile
index 7de677741..293418ed5 100644
--- a/tests/writer.textile
+++ b/tests/writer.textile
@@ -30,7 +30,7 @@ h1(#paragraphs). Paragraphs
Here's a regular paragraph.
-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.
+In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item. Because a hard&#45;wrapped line in the middle of a paragraph looked like a list item.
Here's one with a bullet. &#42; criminey.
@@ -41,7 +41,7 @@ here.
h1(#block-quotes). Block Quotes
-E-mail style:
+E&#45;mail style:
bq. This is a block quote. It is pretty short.
@@ -527,7 +527,7 @@ h1(#latex). LaTeX
* <span class="math">x \in y</math>
* <span class="math">\alpha \wedge \omega</math>
* <span class="math">223</math>
-* <span class="math">p</math>-Tree
+* <span class="math">p</math>&#45;Tree
* Here's some display math: <span class="math">\frac{d}{dx}f(x)=\lim_{h\to 0}\frac{f(x+h)-f(x)}{h}</math>
* Here's one that has a line break in it: <span class="math">\alpha + \omega \times x^2</math>.
@@ -583,7 +583,7 @@ Left paren: (
Right paren: )
-Greater-than: &gt;
+Greater&#45;than: &gt;
Hash: #
@@ -591,9 +591,9 @@ Period: .
Bang: !
-Plus: +
+Plus: &#43;
-Minus: -
+Minus: &#45;
<hr />
@@ -664,13 +664,13 @@ With an ampersand: "$":http://example.com/?foo=1&bar=2
* "$":http://example.com/
* It should.
-An e-mail address: "nobody&#64;nowhere.net":mailto:nobody@nowhere.net
+An e&#45;mail address: "nobody&#64;nowhere.net":mailto:nobody@nowhere.net
bq. Blockquoted: "$":http://example.com/
-Auto-links should not occur here: @<http://example.com/>@
+Auto&#45;links should not occur here: @<http://example.com/>@
bc. or here: <http://example.com/>
diff --git a/trypandoc/index.html b/trypandoc/index.html
index 2c9c55ef2..88e020e32 100644
--- a/trypandoc/index.html
+++ b/trypandoc/index.html
@@ -29,11 +29,6 @@ function newpage() {
window.location.href = href.replace(/([?].*)?$/,"?" + $.param({text: input, from: from, to: to}));
};
-function process(res) {
- $("#results").text(res.result);
- $("#version").text(res.version);
-}
-
$(document).ready(function() {
var text = $.QueryString["text"];
$("#text").val(text);
@@ -42,7 +37,12 @@ $(document).ready(function() {
var to = $.QueryString["to"] || "html";
$("#to").val(to);
if (text && text != "") {
- $.getJSON("http://johnmacfarlane.net/cgi-bin/trypandoc", { from: from, to: to, text: text }, process);
+ $.getJSON("/cgi-bin/trypandoc", { from: from, to: to, text: text },
+ function(res) {
+ $("#results").text(res.result);
+ $("#version").text(res.version);
+ $("#command").text("pandoc --from " + from + " --to " + to);
+ });
};
$("#convert").click(newpage);
});
@@ -57,15 +57,23 @@ $(document).ready(function() {
footer { color: #555; text-align: center; margin: 1em; }
p.version { color: #555; }
button#convert { vertical-align: bottom; }
+ pre#command { margin-top: 1em; background-color: transparent; border: none; }
</style>
</head>
<body>
<div class="container">
<div class="row">
- <h1>Try <a href="http://johnmacfarlane.net/pandoc/">pandoc</a>!</h1>
+ <div class="col-md-6">
+ <h1>Try <a href="http://pandoc.org">pandoc</a>!</h1>
+ </div>
+ <div class="col-md-6">
+ <pre id="command"></pre>
+ </div>
</div>
<div class="row">
<div class="col-md-6">
+ <button class="btn btn-primary btn-xs" id="convert">Convert</button>
+ &nbsp;
<label for="from">
from
</label>
@@ -73,7 +81,7 @@ $(document).ready(function() {
<option value="markdown" selected>Markdown</option>
<option value="markdown_strict">Markdown/strict</option>
<option value="markdown_phpextra">PHP Markdown Extra</option>
- <option value="markdown_github">Github Markdown</option>
+ <option value="markdown_github">GitHub Markdown</option>
<option value="markdown_mmd">MultiMarkdown</option>
<option value="rst">reStructuredText</option>
<option value="textile">Textile</option>
@@ -99,7 +107,7 @@ $(document).ready(function() {
<option value="markdown">Markdown</option>
<option value="markdown_strict">Markdown/strict</option>
<option value="markdown_phpextra">PHP Markdown Extra</option>
- <option value="markdown_github">Github Markdown</option>
+ <option value="markdown_github">GitHub Markdown</option>
<option value="markdown_mmd">MultiMarkdown</option>
<option value="rst">reStructuredText</option>
<option value="asciidoc">AsciiDoc</option>
@@ -122,8 +130,6 @@ $(document).ready(function() {
<option value="S5">S5</option>
<option value="slideous">Slideous</option>
</select>
- &nbsp;
- <button class="btn btn-primary btn-xs" id="convert">Convert</button>
<br/>
<pre id="results"></pre>
</div>
diff --git a/trypandoc/trypandoc.hs b/trypandoc/trypandoc.hs
index c530f45f2..8f1b3278e 100644
--- a/trypandoc/trypandoc.hs
+++ b/trypandoc/trypandoc.hs
@@ -8,6 +8,7 @@ import Network.HTTP.Types.Status (status200)
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.URI (queryToQueryText)
import Text.Pandoc
+import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Shared (tabFilter)
import Text.Highlighting.Kate (pygments)
import Data.Aeson
@@ -29,7 +30,9 @@ app req respond = do
$ lookup fromFormat fromFormats
let writer = maybe (error $ "could not find writer for " ++ T.unpack toFormat) id
$ lookup toFormat toFormats
- let result = T.pack $ writer $ reader $ tabFilter 4 $ T.unpack text
+ let result = case reader $ tabFilter 4 $ T.unpack text of
+ Right doc -> T.pack $ writer doc
+ Left err -> error (show err)
let output = encode $ object [ T.pack "result" .= result
, T.pack "name" .=
if fromFormat == "markdown_strict"
@@ -55,7 +58,7 @@ readerOpts :: ReaderOptions
readerOpts = def { readerParseRaw = True,
readerSmart = True }
-fromFormats :: [(Text, String -> Pandoc)]
+fromFormats :: [(Text, String -> Either PandocError Pandoc)]
fromFormats = [
("native" , readNative)
,("json" , Text.Pandoc.readJSON readerOpts)
diff --git a/windows/make-windows-installer.bat b/windows/make-windows-installer.bat
index d4816fa69..d9c5d3883 100644
--- a/windows/make-windows-installer.bat
+++ b/windows/make-windows-installer.bat
@@ -28,7 +28,7 @@ cd windows
echo Creating msi...
candle -dVERSION=%VERSION% pandoc.wxs
if %errorlevel% neq 0 exit /b %errorlevel%
-light -sw1076 -ext WixUIExtension -out pandoc-%VERSION%-windows.msi pandoc.wixobj
+light -sw1076 -ext WixUIExtension -ext WixUtilExtension -out pandoc-%VERSION%-windows.msi pandoc.wixobj
if %errorlevel% neq 0 exit /b %errorlevel%
echo Starting kSign: sign, then quit kSign to complete the build...
kSign
diff --git a/windows/pandoc.wxs b/windows/pandoc.wxs
index 75c316772..c1465ffcf 100644
--- a/windows/pandoc.wxs
+++ b/windows/pandoc.wxs
@@ -1,124 +1,217 @@
-<?xml version="1.0"?>
-<?define UpgradeCode = "A68E8EF6-ABB1-4F22-A3C5-68DFDF0AB562" ?>
-<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
- <Product Id="*"
- UpgradeCode="$(var.UpgradeCode)" Name="Pandoc $(var.VERSION)"
- Version="$(var.VERSION)" Manufacturer="John MacFarlane"
- Language="1033">
-
- <Package InstallerVersion="200" Compressed="yes" InstallScope="perUser"
- Comments="Windows Installer Package" />
- <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
- <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
- <Upgrade Id="$(var.UpgradeCode)">
- <UpgradeVersion Property='PREVIOUSVERSIONSINSTALLED'
- Minimum='0.0.0.0' IncludeMinimum='yes'
- Maximum="99.0.0.0" IncludeMaximum="no" />
- </Upgrade>
- <Property Id="ARPURLINFOABOUT" Value="http://johnmacfarlane.net/pandoc/" />
-
- <InstallExecuteSequence>
- <RemoveExistingProducts After="InstallFinalize"/>
- </InstallExecuteSequence>
-
- <Property Id="DISABLEADVTSHORTCUTS" Value="1" />
-
- <CustomAction Id="SetPerUserFolder" Property="APPLICATIONFOLDER" Value="[LocalAppDataFolder]Pandoc" Execute="immediate" />
- <CustomAction Id="SetPerMachineFolder" Property="APPLICATIONFOLDER" Value="[ProgramFilesFolder]Pandoc" Execute="immediate" />
- <InstallExecuteSequence>
- <Custom Action="SetPerUserFolder" Before="CostFinalize">ACTION="INSTALL" AND APPLICATIONFOLDER="" AND (ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged)))</Custom>
- <Custom Action="SetPerMachineFolder" After="SetPerUserFolder">ACTION="INSTALL" AND APPLICATIONFOLDER="" AND (ALLUSERS=1 OR (ALLUSERS=2 AND Privileged))</Custom>
- </InstallExecuteSequence>
- <InstallUISequence>
- <Custom Action="SetPerUserFolder" Before="CostFinalize">ACTION="INSTALL" AND APPLICATIONFOLDER="" AND (ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged)))</Custom>
- <Custom Action="SetPerMachineFolder" After="SetPerUserFolder">ACTION="INSTALL" AND APPLICATIONFOLDER="" AND (ALLUSERS=1 OR (ALLUSERS=2 AND Privileged))</Custom>
- </InstallUISequence>
-
- <Directory Id="TARGETDIR" Name="SourceDir">
-
- <Directory Id="ProgramFilesFolder">
- <Directory Id="APPLICATIONFOLDER" Name="Pandoc">
- <Component Id="MainExecutable"
- Guid="ECD35082-4C28-49E1-977E-B90FC7C400C7">
- <RegistryValue Root="HKMU" Key="Software\John MacFarlane\Pandoc"
- Name="Version" Type="string" Value="[ProductVersion]" KeyPath="yes"/>
- <RemoveFolder Id="APPLICATIONFOLDER" On="uninstall"/>
- <File Id="pandocEXE" Name="pandoc.exe"
- Source="..\.cabal-sandbox\bin\pandoc.exe" />
- <File Id="pandocCOPYRIGHT" Name="COPYRIGHT.txt"
- Source="..\COPYRIGHT.txt" />
- <File Id="pandocCOPYING" Name="COPYING.rtf"
- Source="..\COPYING.rtf" />
- </Component>
-
- <Component Id="CitationSupport"
- Guid="0A214839-2E69-4026-8DBB-0F0A9DB75C12">
- <RegistryValue Root="HKMU" Key="Software\John MacFarlane\Pandoc"
- Name="Version" Type="string" Value="[ProductVersion]" KeyPath="yes"/>
- <File Id="pandoc_citeprocEXE" Name="pandoc-citeproc.exe"
- Source="..\.cabal-sandbox\bin\pandoc-citeproc.exe" />
- </Component>
-
- <Component Id="UpdatePathUser"
- Guid="C7B71304-09FC-421D-9EA2-AEFB7D61759D">
- <Condition><![CDATA[ ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged)) ]]></Condition>
- <Environment Id="UpdatePathUser" Name="PATH" Action="set"
- Part="last" Value="[APPLICATIONFOLDER]" System="no" />
- <RegistryValue Root="HKCU" Key="Software\John MacFarlane\Pandoc"
- Name="UserPathUpdated" Type="integer" Value="1" KeyPath="yes"/>
- </Component>
-
- <Component Id="UpdatePathMachine"
- Guid="0C642D0A-7175-4CD7-B11F-0A69F73FD757">
- <Condition><![CDATA[ ALLUSERS=1 OR (ALLUSERS=2 AND Privileged) ]]></Condition>
- <Environment Id="UpdatePathMachine" Name="PATH" Action="set"
- Part="last" Value="[APPLICATIONFOLDER]" System="yes" />
- <RegistryValue Root="HKLM" Key="Software\John MacFarlane\Pandoc"
- Name="SystemPathUpdated" Type="integer" Value="1" KeyPath="yes"/>
- </Component>
-
- <Component Id="Documentation"
- Guid="A8D54A76-1A3D-4647-8327-81B69D39D8A3">
- <File Id="pandocREADME" Name="Pandoc User's Guide.html"
- Source="..\README.html" KeyPath="yes">
- <Shortcut Id="ApplicationStartMenuShortcut" Directory="ApplicationProgramsFolder"
- Name="Pandoc User’s Guide" Advertise="yes" />
- </File>
- </Component>
- </Directory>
- </Directory>
-
- <Directory Id="ProgramMenuFolder">
- <Directory Id="ApplicationProgramsFolder" Name="Pandoc">
- <Component Id="ApplicationShortcut" Guid="7F807DD5-CC54-474A-B571-89630893F563">
- <RemoveFolder Id="ApplicationProgramsFolder" On="uninstall"/>
- <RegistryValue Root="HKMU" Key="Software\John MacFarlane\Pandoc"
- Name="ShortcutInstalled" Type="integer" Value="1" KeyPath="yes"/>
- </Component>
- </Directory>
- </Directory>
-
- </Directory>
-
- <Feature Id="Complete" Level="1" Title="Pandoc $(var.VERSION)" Description="Complete package" Display="expand" ConfigurableDirectory="APPLICATIONFOLDER">
- <Feature Id="MainProgram" Title="Program" Description="The main executable." Level="1">
- <ComponentRef Id="MainExecutable" />
- <ComponentRef Id="UpdatePathUser" />
- <ComponentRef Id="UpdatePathMachine" />
- </Feature>
- <Feature Id="Manual" Title="Manual">
- <ComponentRef Id="Documentation" />
- <ComponentRef Id="ApplicationShortcut" />
- </Feature>
- <Feature Id="Citation" Title="Citation Support" Description="Citation support.">
- <ComponentRef Id="CitationSupport" />
- </Feature>
- </Feature>
-
- <Property Id="WIXUI_INSTALLDIR" Value="APPLICATIONFOLDER" />
- <UIRef Id="WixUI_Minimal" />
- <UIRef Id="WixUI_ErrorProgressText" />
- <WixVariable Id="WixUILicenseRtf" Value="..\COPYING.rtf" />
-
- </Product>
-</Wix>
+<?xml version="1.0"?>
+<?define UpgradeCode = "A68E8EF6-ABB1-4F22-A3C5-68DFDF0AB562" ?>
+<?if $(sys.BUILDARCH)=x64?>
+ <?define ProgFilesFolder="ProgramFiles64Folder"?>
+<?else?>
+ <?define ProgFilesFolder="ProgramFilesFolder"?>
+<?endif?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
+ <Product Id="*"
+ UpgradeCode="$(var.UpgradeCode)" Name="Pandoc $(var.VERSION)"
+ Version="$(var.VERSION)" Manufacturer="John MacFarlane"
+ Language="1033">
+
+ <Package InstallerVersion="200" Compressed="yes"
+ Comments="Windows Installer Package" />
+ <Media Id="1" Cabinet="product.cab" EmbedCab="yes" />
+ <Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
+ <Upgrade Id="$(var.UpgradeCode)">
+ <UpgradeVersion Property='PREVIOUSVERSIONSINSTALLED'
+ Minimum='0.0.0.0' IncludeMinimum='yes'
+ Maximum="99.0.0.0" IncludeMaximum="no" />
+ </Upgrade>
+ <Property Id="ARPURLINFOABOUT" Value="http://pandoc.org" />
+
+ <InstallExecuteSequence>
+ <RemoveExistingProducts After="InstallFinalize"/>
+ </InstallExecuteSequence>
+
+ <Property Id="DISABLEADVTSHORTCUTS" Value="1" />
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+
+ <Directory Id="$(var.ProgFilesFolder)">
+ <Directory Id="APPLICATIONFOLDER" Name="Pandoc">
+ <Component Id="MainExecutable"
+ Guid="ECD35082-4C28-49E1-977E-B90FC7C400C7">
+ <RegistryValue Root="HKMU"
+ Key="Software\John MacFarlane\Pandoc"
+ Name="Version" Type="string" Value="[ProductVersion]"
+ KeyPath="yes"/>
+ <RemoveFolder Id="APPLICATIONFOLDER" On="uninstall"/>
+ <File Id="pandocEXE" Name="pandoc.exe"
+ Source="..\.cabal-sandbox\bin\pandoc.exe" />
+ <File Id="pandocCOPYRIGHT" Name="COPYRIGHT.txt"
+ Source="..\COPYRIGHT.txt" />
+ <File Id="pandocCOPYING" Name="COPYING.rtf"
+ Source="..\COPYING.rtf" />
+ </Component>
+
+ <Component Id="CitationSupport"
+ Guid="0A214839-2E69-4026-8DBB-0F0A9DB75C12">
+ <RegistryValue Root="HKMU"
+ Key="Software\John MacFarlane\Pandoc"
+ Name="Version" Type="string" Value="[ProductVersion]"
+ KeyPath="yes"/>
+ <File Id="pandoc_citeprocEXE" Name="pandoc-citeproc.exe"
+ Source="..\.cabal-sandbox\bin\pandoc-citeproc.exe" />
+ </Component>
+
+ <Component Id="Documentation"
+ Guid="A8D54A76-1A3D-4647-8327-81B69D39D8A3">
+ <File Id="pandocREADME" Name="Pandoc User's Guide.html"
+ Source="..\README.html" KeyPath="yes">
+ <Shortcut Id="ApplicationStartMenuShortcut"
+ Directory="ApplicationProgramsFolder"
+ Name="Pandoc User’s Guide" Advertise="yes" />
+ </File>
+ </Component>
+
+
+ <Component Id="UpdateUserPath"
+ Guid="7ECEAD05-CA5C-4147-82CB-F7CADABAC7F3"
+ KeyPath="yes">
+ <Condition>ALLUSERS = "" OR ALLUSERS = 2</Condition>
+ <Environment Id='SetUserPath' Name='PATH' Action='set'
+ Permanent='no' System='no' Part='last'
+ Value='[APPLICATIONFOLDER]' />
+ </Component>
+
+ <Component Id="UpdateSystemPath"
+ Guid="F8AC4135-C0AE-48C7-BAC5-311DAC97CFD8"
+ KeyPath="yes">
+ <Condition>ALLUSERS = 1</Condition>
+ <Environment Id='SetSystemPath' Name='PATH' Action='set'
+ Permanent='no' System='yes' Part='last'
+ Value='[APPLICATIONFOLDER]' />
+ </Component>
+
+ </Directory>
+ </Directory>
+
+ <Directory Id="ProgramMenuFolder">
+ <Directory Id="ApplicationProgramsFolder" Name="Pandoc">
+ <Component Id="ApplicationShortcut"
+ Guid="7F807DD5-CC54-474A-B571-89630893F563">
+ <RemoveFolder Id="ApplicationProgramsFolder"
+ On="uninstall"/>
+ <RegistryValue Root="HKMU" Key="Software\John MacFarlane\Pandoc"
+ Name="ShortcutInstalled" Type="integer" Value="1"
+ KeyPath="yes"/>
+ </Component>
+ </Directory>
+ </Directory>
+
+ </Directory>
+
+ <Feature Id="Complete" Level="1" Title="Pandoc $(var.VERSION)"
+ Description="Complete package" Display="expand"
+ ConfigurableDirectory="APPLICATIONFOLDER">
+ <Feature Id="MainProgram"
+ Title="Program"
+ Description="The main executable."
+ Level="1">
+ <ComponentRef Id="MainExecutable" />
+ <ComponentRef Id="UpdateUserPath" />
+ <ComponentRef Id="UpdateSystemPath" />
+ </Feature>
+ <Feature Id="Manual" Title="Manual">
+ <ComponentRef Id="Documentation" />
+ <ComponentRef Id="ApplicationShortcut" />
+ </Feature>
+ <Feature Id="Citation" Title="Citation Support"
+ Description="Citation support.">
+ <ComponentRef Id="CitationSupport" />
+ </Feature>
+ </Feature>
+
+
+ <SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]"
+ After="CostFinalize" />
+
+ <CustomAction Id="SetExitDialogOptText"
+ Property="WIXUI_EXITDIALOGOPTIONALTEXT"
+ Value="[ProductName] was installed in [APPLICATIONFOLDER]. You may need to restart Cmd/Powershell windows before using it." />
+
+ <CustomAction Id="CustomWixSetPerUserFolder"
+ Property="WixPerUserFolder"
+ Value="[LocalAppDataFolder][ApplicationFolderName]"
+ Execute="immediate" />
+
+
+ <InstallExecuteSequence>
+ <Custom Action="CustomWixSetPerUserFolder" After="WixSetDefaultPerUserFolder">
+ ACTION="INSTALL" AND (ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged)))
+ </Custom>
+ </InstallExecuteSequence>
+
+ <InstallUISequence>
+ <Custom Action="SetExitDialogOptText" Before="ExecuteAction">
+ NOT Installed
+ </Custom>
+ <Custom Action="CustomWixSetPerUserFolder" After="WixSetDefaultPerUserFolder">
+ ACTION="INSTALL" AND (ALLUSERS="" OR (ALLUSERS=2 AND (NOT Privileged)))
+ </Custom>
+ </InstallUISequence>
+
+ <CustomActionRef Id="WixBroadcastSettingChange" />
+ <CustomActionRef Id="WixBroadcastEnvironmentChange" />
+
+ <Property Id="ApplicationFolderName" Value="Pandoc" />
+ <Property Id="WixAppFolder" Value="WixPerUserFolder" />
+ <Property Id="ALLUSERS" Value="2" Secure="yes" />
+ <Property Id="MSIINSTALLPERUSER" Value="1" />
+
+ <WixVariable Id="WixUILicenseRtf" Value="..\COPYING.rtf" />
+
+ <UI Id="MyWixUI_Advanced">
+ <UIRef Id="WixUI_Advanced" />
+ <UIRef Id="WixUI_ErrorProgressText" />
+
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Event="NewDialog" Value="VerifyReadyDlg"
+ Order="6">WixAppFolder = "WixPerUserFolder"</Publish>
+
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Property="APPLICATIONFOLDER"
+ Value="[$(var.ProgFilesFolder)][ApplicationFolderName]"
+ Order="7">WixAppFolder = "WixPerMachineFolder"</Publish>
+
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Property="APPLICATIONFOLDER" Value="[LocalAppDataFolder][ApplicationFolderName]"
+ Order="8">WixAppFolder = "WixPerUserFolder"</Publish>
+
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Property="MSIINSTALLPERUSER" Value="{}"
+ Order="18">WixAppFolder = "WixPerMachineFolder" AND ALLUSERS = 1</Publish>
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Property="MSIINSTALLPERUSER" Value="1"
+ Order="19">WixAppFolder = "WixPerUserFolder" AND ALLUSERS = 2</Publish>
+ <Publish Dialog="InstallScopeDlg" Control="Next"
+ Property="ALLUSERS" Value="2"
+ Order="20">WixAppFolder = "WixPerUserFolder"</Publish>
+
+
+ <Publish Dialog="InstallDirDlg" Control="Next"
+ Event="NewDialog" Value="VerifyReadyDlg"
+ Order="4">
+ WIXUI_DONTVALIDATEPATH OR
+ WIXUI_INSTALLDIR_VALID="1"
+ </Publish>
+
+ <Publish Dialog="VerifyReadyDlg" Control="Back"
+ Event="NewDialog" Value="InstallScopeDlg"
+ Order="11">
+ WixAppFolder = "WixPerUserFolder"
+ </Publish>
+ <Publish Dialog="VerifyReadyDlg" Control="Back"
+ Event="NewDialog" Value="InstallDirDlg"
+ Order="12">
+ WixAppFolder = "WixPerMachineFolder"
+ </Publish>
+ </UI>
+
+ </Product>
+
+</Wix>