aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml3
-rw-r--r--COPYRIGHT36
-rw-r--r--MANUAL.txt140
-rw-r--r--Makefile12
-rw-r--r--README.md2
-rw-r--r--appveyor.yml57
-rw-r--r--benchmark/benchmark-pandoc.hs18
-rw-r--r--benchmark/weigh-pandoc.hs7
-rw-r--r--data/docx/word/styles.xml9
-rw-r--r--data/pandoc.lua40
-rw-r--r--data/templates/default.beamer2
-rw-r--r--data/templates/default.context25
-rw-r--r--data/templates/default.latex49
-rw-r--r--linux/control.in22
-rwxr-xr-xmacos/make_macos_package.sh18
-rw-r--r--man/pandoc.1533
-rw-r--r--pandoc.cabal29
-rw-r--r--pandoc.hs7
-rw-r--r--src/Text/Pandoc.hs4
-rw-r--r--src/Text/Pandoc/App.hs207
-rw-r--r--src/Text/Pandoc/Asciify.hs4
-rw-r--r--src/Text/Pandoc/CSS.hs2
-rw-r--r--src/Text/Pandoc/Class.hs126
-rw-r--r--src/Text/Pandoc/Compat/Time.hs2
-rw-r--r--src/Text/Pandoc/Error.hs13
-rw-r--r--src/Text/Pandoc/Extensions.hs7
-rw-r--r--src/Text/Pandoc/Highlighting.hs10
-rw-r--r--src/Text/Pandoc/ImageSize.hs83
-rw-r--r--src/Text/Pandoc/Logging.hs30
-rw-r--r--src/Text/Pandoc/Lua.hs18
-rw-r--r--src/Text/Pandoc/Lua/Compat.hs4
-rw-r--r--src/Text/Pandoc/Lua/PandocModule.hs31
-rw-r--r--src/Text/Pandoc/Lua/SharedInstances.hs14
-rw-r--r--src/Text/Pandoc/Lua/StackInstances.hs16
-rw-r--r--src/Text/Pandoc/Lua/Util.hs8
-rw-r--r--src/Text/Pandoc/MIME.hs4
-rw-r--r--src/Text/Pandoc/MediaBag.hs35
-rw-r--r--src/Text/Pandoc/Options.hs38
-rw-r--r--src/Text/Pandoc/PDF.hs109
-rw-r--r--src/Text/Pandoc/Parsing.hs242
-rw-r--r--src/Text/Pandoc/Pretty.hs8
-rw-r--r--src/Text/Pandoc/Process.hs4
-rw-r--r--src/Text/Pandoc/Readers.hs48
-rw-r--r--src/Text/Pandoc/Readers/CommonMark.hs6
-rw-r--r--src/Text/Pandoc/Readers/DocBook.hs8
-rw-r--r--src/Text/Pandoc/Readers/Docx.hs4
-rw-r--r--src/Text/Pandoc/Readers/Docx/Lists.hs4
-rw-r--r--src/Text/Pandoc/Readers/Docx/Parse.hs4
-rw-r--r--src/Text/Pandoc/Readers/EPUB.hs4
-rw-r--r--src/Text/Pandoc/Readers/HTML.hs418
-rw-r--r--src/Text/Pandoc/Readers/Haddock.hs5
-rw-r--r--src/Text/Pandoc/Readers/LaTeX.hs216
-rw-r--r--src/Text/Pandoc/Readers/Markdown.hs224
-rw-r--r--src/Text/Pandoc/Readers/MediaWiki.hs24
-rw-r--r--src/Text/Pandoc/Readers/Native.hs25
-rw-r--r--src/Text/Pandoc/Readers/OPML.hs10
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/State.hs90
-rw-r--r--src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs272
-rw-r--r--src/Text/Pandoc/Readers/Odt/ContentReader.hs5
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs129
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/Utils.hs7
-rw-r--r--src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs320
-rw-r--r--src/Text/Pandoc/Readers/Odt/StyleReader.hs83
-rw-r--r--src/Text/Pandoc/Readers/Org.hs11
-rw-r--r--src/Text/Pandoc/Readers/Org/BlockStarts.hs21
-rw-r--r--src/Text/Pandoc/Readers/Org/Blocks.hs390
-rw-r--r--src/Text/Pandoc/Readers/Org/DocumentTree.hs304
-rw-r--r--src/Text/Pandoc/Readers/Org/ExportSettings.hs8
-rw-r--r--src/Text/Pandoc/Readers/Org/Inlines.hs129
-rw-r--r--src/Text/Pandoc/Readers/Org/Meta.hs40
-rw-r--r--src/Text/Pandoc/Readers/Org/ParserState.hs53
-rw-r--r--src/Text/Pandoc/Readers/Org/Parsing.hs10
-rw-r--r--src/Text/Pandoc/Readers/Org/Shared.hs8
-rw-r--r--src/Text/Pandoc/Readers/RST.hs172
-rw-r--r--src/Text/Pandoc/Readers/TWiki.hs19
-rw-r--r--src/Text/Pandoc/Readers/Textile.hs31
-rw-r--r--src/Text/Pandoc/Readers/Txt2Tags.hs20
-rw-r--r--src/Text/Pandoc/SelfContained.hs83
-rw-r--r--src/Text/Pandoc/Shared.hs146
-rw-r--r--src/Text/Pandoc/Slides.hs4
-rw-r--r--src/Text/Pandoc/Templates.hs4
-rw-r--r--src/Text/Pandoc/UTF8.hs99
-rw-r--r--src/Text/Pandoc/UUID.hs4
-rw-r--r--src/Text/Pandoc/Writers.hs97
-rw-r--r--src/Text/Pandoc/Writers/AsciiDoc.hs15
-rw-r--r--src/Text/Pandoc/Writers/CommonMark.hs13
-rw-r--r--src/Text/Pandoc/Writers/ConTeXt.hs19
-rw-r--r--src/Text/Pandoc/Writers/Custom.hs12
-rw-r--r--src/Text/Pandoc/Writers/Docbook.hs18
-rw-r--r--src/Text/Pandoc/Writers/Docx.hs51
-rw-r--r--src/Text/Pandoc/Writers/DokuWiki.hs14
-rw-r--r--src/Text/Pandoc/Writers/EPUB.hs9
-rw-r--r--src/Text/Pandoc/Writers/FB2.hs26
-rw-r--r--src/Text/Pandoc/Writers/HTML.hs81
-rw-r--r--src/Text/Pandoc/Writers/Haddock.hs16
-rw-r--r--src/Text/Pandoc/Writers/ICML.hs15
-rw-r--r--src/Text/Pandoc/Writers/JATS.hs14
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs26
-rw-r--r--src/Text/Pandoc/Writers/Man.hs34
-rw-r--r--src/Text/Pandoc/Writers/Markdown.hs116
-rw-r--r--src/Text/Pandoc/Writers/MediaWiki.hs13
-rw-r--r--src/Text/Pandoc/Writers/Ms.hs16
-rw-r--r--src/Text/Pandoc/Writers/Muse.hs26
-rw-r--r--src/Text/Pandoc/Writers/Native.hs7
-rw-r--r--src/Text/Pandoc/Writers/ODT.hs15
-rw-r--r--src/Text/Pandoc/Writers/OPML.hs19
-rw-r--r--src/Text/Pandoc/Writers/OpenDocument.hs14
-rw-r--r--src/Text/Pandoc/Writers/Org.hs51
-rw-r--r--src/Text/Pandoc/Writers/RST.hs46
-rw-r--r--src/Text/Pandoc/Writers/RTF.hs16
-rw-r--r--src/Text/Pandoc/Writers/Shared.hs22
-rw-r--r--src/Text/Pandoc/Writers/TEI.hs14
-rw-r--r--src/Text/Pandoc/Writers/Texinfo.hs19
-rw-r--r--src/Text/Pandoc/Writers/Textile.hs15
-rw-r--r--src/Text/Pandoc/Writers/ZimWiki.hs18
-rw-r--r--src/Text/Pandoc/XML.hs15
-rw-r--r--stack.full.yaml1
-rw-r--r--stack.pkg.yaml5
-rw-r--r--stack.yaml3
-rw-r--r--test/Tests/Command.hs9
-rw-r--r--test/Tests/Helpers.hs11
-rw-r--r--test/Tests/Lua.hs6
-rw-r--r--test/Tests/Readers/Docx.hs7
-rw-r--r--test/Tests/Readers/HTML.hs3
-rw-r--r--test/Tests/Readers/LaTeX.hs14
-rw-r--r--test/Tests/Readers/Markdown.hs48
-rw-r--r--test/Tests/Readers/Odt.hs10
-rw-r--r--test/Tests/Readers/Org.hs1066
-rw-r--r--test/Tests/Readers/RST.hs24
-rw-r--r--test/Tests/Readers/Txt2Tags.hs78
-rw-r--r--test/Tests/Writers/AsciiDoc.hs3
-rw-r--r--test/Tests/Writers/ConTeXt.hs5
-rw-r--r--test/Tests/Writers/Docbook.hs3
-rw-r--r--test/Tests/Writers/Docx.hs6
-rw-r--r--test/Tests/Writers/HTML.hs3
-rw-r--r--test/Tests/Writers/LaTeX.hs5
-rw-r--r--test/Tests/Writers/Markdown.hs5
-rw-r--r--test/Tests/Writers/Muse.hs21
-rw-r--r--test/Tests/Writers/Native.hs6
-rw-r--r--test/command/1718.md11
-rw-r--r--test/command/1841.md42
-rw-r--r--test/command/2228.md6
-rw-r--r--test/command/2602.md18
-rw-r--r--test/command/3113.md13
-rw-r--r--test/command/3314.md34
-rw-r--r--test/command/3401.md19
-rw-r--r--test/command/3432.md289
-rw-r--r--test/command/3450.md12
-rw-r--r--test/command/3494.md2
-rw-r--r--test/command/3510-export.latex1
-rw-r--r--test/command/3510-src.hs1
-rw-r--r--test/command/3510-subdoc.org5
-rw-r--r--test/command/3510.md20
-rw-r--r--test/command/3516.md4
-rw-r--r--test/command/3577.md2
-rw-r--r--test/command/3585.md16
-rw-r--r--test/command/3619.md28
-rw-r--r--test/command/3630.md8
-rw-r--r--test/command/3667.md13
-rw-r--r--test/command/3674.md39
-rw-r--r--test/command/3675.md15
-rw-r--r--test/command/3690.md8
-rw-r--r--test/command/3701.md60
-rw-r--r--test/command/3706.md44
-rw-r--r--test/command/3708.md15
-rw-r--r--test/command/3715.md15
-rw-r--r--test/command/3716.md6
-rw-r--r--test/command/3730.md21
-rw-r--r--test/command/3736.md25
-rw-r--r--test/command/512.md1
-rw-r--r--test/command/SVG_logo-without-xml-declaration.svg32
-rw-r--r--test/command/SVG_logo.svg33
-rw-r--r--test/command/corrupt.svg5
-rw-r--r--test/command/inkscape-cube.svg119
-rw-r--r--test/command/latex-fontawesome.md13
-rw-r--r--test/command/lstlisting.md25
-rw-r--r--test/command/parse-raw.md3
-rw-r--r--test/command/svg.md132
-rw-r--r--test/command/tabularx.md110
-rw-r--r--test/fb2/titles.fb22
-rw-r--r--test/fb2/titles.markdown4
-rw-r--r--test/latex-reader.native4
-rw-r--r--test/lhs-test.latex12
-rw-r--r--test/lhs-test.latex+lhs12
-rw-r--r--test/markdown-reader-more.native68
-rw-r--r--test/tables-rstsubset.native12
-rw-r--r--test/tables.muse52
-rw-r--r--test/testsuite.native2
-rw-r--r--test/testsuite.txt11
-rw-r--r--test/writer.asciidoc4
-rw-r--r--test/writer.context53
-rw-r--r--test/writer.docbook46
-rw-r--r--test/writer.docbook56
-rw-r--r--test/writer.dokuwiki4
-rw-r--r--test/writer.fb21014
-rw-r--r--test/writer.haddock4
-rw-r--r--test/writer.html42
-rw-r--r--test/writer.html52
-rw-r--r--test/writer.icml126
-rw-r--r--test/writer.jats6
-rw-r--r--test/writer.latex16
-rw-r--r--test/writer.man4
-rw-r--r--test/writer.markdown4
-rw-r--r--test/writer.mediawiki4
-rw-r--r--test/writer.ms10
-rw-r--r--test/writer.muse44
-rw-r--r--test/writer.native2
-rw-r--r--test/writer.opendocument4
-rw-r--r--test/writer.opml2
-rw-r--r--test/writer.org4
-rw-r--r--test/writer.plain4
-rw-r--r--test/writer.rst10
-rw-r--r--test/writer.rtf8
-rw-r--r--test/writer.tei2
-rw-r--r--test/writer.texinfo4
-rw-r--r--test/writer.textile4
-rw-r--r--test/writer.zimwiki4
-rw-r--r--test/writers-lang-and-dir.context13
-rw-r--r--test/writers-lang-and-dir.latex39
-rw-r--r--trypandoc/trypandoc.hs68
220 files changed, 6514 insertions, 4141 deletions
diff --git a/.travis.yml b/.travis.yml
index 26557f6f8..1b9b9a095 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -34,6 +34,7 @@ matrix:
- env: BUILD=cabal GHCVER=7.8.4 CABALVER=1.18
compiler: ": #GHC 7.8.4"
addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4,happy-1.19.5], sources: [hvr-ghc]}}
+
- env: BUILD=cabal GHCVER=7.10.3 CABALVER=1.22
compiler: ": #GHC 7.10.3"
addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3,happy-1.19.5], sources: [hvr-ghc]}}
@@ -100,13 +101,11 @@ install:
case "$BUILD" in
stack)
ulimit -n 4096
- stack --no-terminal install hsb2hs
stack --no-terminal --install-ghc $ARGS test --flag 'aeson:fast' --only-dependencies --fast --flag pandoc:embed_data_files --test
;;
cabal)
cabal --version
travis_retry cabal update
- cabal install hsb2hs
cabal install -j --only-dependencies -ffast --enable-tests --enable-benchmarks -fembed_data_files --force-reinstalls --ghc-options=-O0 --reorder-goals --max-backjumps=-1 $CABALARGS
;;
esac
diff --git a/COPYRIGHT b/COPYRIGHT
index 9d6a78da5..2cc57f6f5 100644
--- a/COPYRIGHT
+++ b/COPYRIGHT
@@ -32,33 +32,53 @@ statements for these sources are included below. All are GPL-compatible
licenses.
----------------------------------------------------------------------
+src/Text/Pandoc/Writers/Muse.hs
+Copyright (C) 2017 Alexander Krotov
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
src/Text/Pandoc/Writers/Texinfo.hs
-Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+Copyright (C) 2008-2017 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-2015 Andrea Rossato and John MacFarlane
+Copyright (C) 2008-2017 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-2015 Puneeth Chaganti and John MacFarlane
+Copyright (C) 2010-2017 Puneeth Chaganti, John MacFarlane, and
+ Albert Krewinkel
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
+src/Text/Pandoc/Writers/ZimWiki.hs
+Copyright (C) 2017 Alex Ivkin
+
+Released under the GNU General Public License version 2 or later.
+
+----------------------------------------------------------------------
+src/Text/Pandoc/Readers/Docx.hs
+src/Text/Pandoc/Readers/Docx/*
+Copyright (C) 2014-2017 Jesse Rosenthal
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Textile.hs
-Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
+Copyright (C) 2010-2017 Paul Rivier and John MacFarlane
Released under the GNU General Public License version 2 or later.
----------------------------------------------------------------------
src/Text/Pandoc/Readers/Org.hs
test/Tests/Readers/Org.hs
-Copyright (C) 2014-2015 Albert Krewinkel
+Copyright (C) 2014-2017 Albert Krewinkel
Released under the GNU General Public License version 2 or later.
@@ -77,6 +97,12 @@ Copyright (C) 2004 Peter Jipsen http://www.chapman.edu/~jipsen
Released under the GNU General Public License version 2 or later.
------------------------------------------------------------------------
+data/pandoc.lua
+Copyright (C) 2017 Albert Krewinkel
+
+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/paulrouget/dzslides
diff --git a/MANUAL.txt b/MANUAL.txt
index 9b5c27b77..df08e4b40 100644
--- a/MANUAL.txt
+++ b/MANUAL.txt
@@ -523,10 +523,15 @@ Reader options
`--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.
- This option only affects the docx and epub readers.
+: Extract images and other media contained in or linked from
+ the source document to the path *DIR*, creating it if
+ necessary, and adjust the images references in the document
+ so they point to the extracted files. If the source format is
+ a binary container (docx, epub, or odt), the media is
+ extracted from the container and the original
+ filenames are used. Otherwise the media is read from the
+ file system or downloaded, and new filenames are constructed
+ based on SHA1 hashes of the contents.
`--abbreviations=`*FILE*
@@ -588,7 +593,15 @@ General writer options
: Print a system default data file. Files in the user data directory
are ignored.
+`--eol=crlf`|`lf`|`native`
+
+: Manually specify line endings: `crlf` (Windows), `lf`
+ (MacOS/linux/unix), or `native` (line endings appropriate
+ to the OS on which pandoc is being run). The default is
+ `native`.
+
`--dpi`=*NUMBER*
+
: Specify the dpi (dots per inch) value for conversion from pixels
to inch/centimeters and vice versa. The default is 96dpi.
Technically, the correct term would be ppi (pixels per inch).
@@ -678,6 +691,18 @@ General writer options
repeatedly to include multiple files. They will be included in the
order specified. Implies `--standalone`.
+`--resource-path=`*SEARCHPATH*
+
+: List of paths to search for images and other resources.
+ The paths should be separated by `:` on linux, unix, and
+ MacOS systems, and by `;` on Windows. If `--resource-path`
+ is not specified, the default resource path is the working
+ directory. Note that, if `--resource-path` is specified,
+ the working directory must be explicitly listed or it
+ will not be searched. For example:
+ `--resource-path=.:test` will search the working directory
+ and the `test` subdirectory, in that order.
+
Options affecting specific writers
----------------------------------
@@ -828,47 +853,51 @@ Options affecting specific writers
: Use the specified file as a style reference in producing a
docx or ODT file.
- Docx: For best results, the reference docx should be a modified
- version of a docx file produced using pandoc. The contents
- of the reference docx are ignored, but its stylesheets and
- document properties (including margins, page size, header,
- and footer) are used in the new docx. If no reference docx
- is specified on the command line, pandoc will look for a
- file `reference.docx` in the user data directory (see
- `--data-dir`). If this is not found either, sensible
- defaults will be used.
-
- To produce a custom `reference.docx`, first get a copy of
- the default `reference.docx`: `pandoc
- --print-default-data-file reference.docx >
- custom-reference.docx`. Then open `custom-reference.docx`
- in Word, modify the styles as you wish, and save the file.
- For best results, do not make changes to this file other
- than modifying the styles used by pandoc: [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,
- Heading 7, Heading 8, Heading 9, 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.
-
- ODT: For best results, the reference ODT should be a modified
- version of an ODT produced using pandoc. The contents of
- the reference ODT are ignored, but its stylesheets are used
- in the new ODT. If no reference ODT is specified on the
- command line, pandoc will look for a file `reference.odt` in
- the user data directory (see `--data-dir`). If this is not
- found either, sensible defaults will be used.
-
- To produce a custom `reference.odt`, first get a copy of
- the default `reference.odt`: `pandoc
- --print-default-data-file reference.odt >
- custom-reference.odt`. Then open `custom-reference.odt` in
- LibreOffice, modify the styles as you wish, and save the
- file.
+ Docx
+
+ : For best results, the reference docx should be a modified
+ version of a docx file produced using pandoc. The contents
+ of the reference docx are ignored, but its stylesheets and
+ document properties (including margins, page size, header,
+ and footer) are used in the new docx. If no reference docx
+ is specified on the command line, pandoc will look for a
+ file `reference.docx` in the user data directory (see
+ `--data-dir`). If this is not found either, sensible
+ defaults will be used.
+
+ To produce a custom `reference.docx`, first get a copy of
+ the default `reference.docx`: `pandoc
+ --print-default-data-file reference.docx >
+ custom-reference.docx`. Then open `custom-reference.docx`
+ in Word, modify the styles as you wish, and save the file.
+ For best results, do not make changes to this file other
+ than modifying the styles used by pandoc: [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,
+ Heading 7, Heading 8, Heading 9, Block Text, Footnote Text,
+ Definition Term, Definition, Caption, Table Caption,
+ Image Caption, Figure, Captioned Figure, TOC Heading;
+ [character] Default Paragraph Font, Body Text Char,
+ Verbatim Char, Footnote Reference, Hyperlink; [table]
+ Table.
+
+ ODT
+
+ : For best results, the reference ODT should be a modified
+ version of an ODT produced using pandoc. The contents of
+ the reference ODT are ignored, but its stylesheets are used
+ in the new ODT. If no reference ODT is specified on the
+ command line, pandoc will look for a file `reference.odt` in
+ the user data directory (see `--data-dir`). If this is not
+ found either, sensible defaults will be used.
+
+ To produce a custom `reference.odt`, first get a copy of
+ the default `reference.odt`: `pandoc
+ --print-default-data-file reference.odt >
+ custom-reference.odt`. Then open `custom-reference.odt` in
+ LibreOffice, modify the styles as you wish, and save the
+ file.
`--epub-cover-image=`*FILE*
@@ -1310,6 +1339,11 @@ including all [reveal.js configuration options].
: color for internal links, citation links, external links, and links in table
of contents: uses any of the [predefined LaTeX colors] (for beamer only).
+`aspectratio`
+: aspect ratio of slides (for beamer only, `1610` for 16:10, `169` for 16:9,
+ `149` for 14:9, `141` for 1.41:1, `54` for 5:4, `43` for 4:3 which is the
+ default, and `32` for 3:2).
+
[reveal.js configuration options]: https://github.com/hakimel/reveal.js#configuration
Variables for LaTeX
@@ -3071,7 +3105,8 @@ definition, which may occur elsewhere in the document (either
before or after the link).
The link consists of link text in square brackets, followed by a label in
-square brackets. (There can be space between the two.) The link definition
+square brackets. (There cannot be space between the two unless the
+`spaced_reference_links` extension is enabled.) The link definition
consists of the bracketed label, followed by a colon and a space, followed by
the URL, and optionally (after a space) a link title either in quotes or in
parentheses. The label must not be parseable as a citation (assuming
@@ -3522,6 +3557,13 @@ implied by pandoc's default `all_symbols_escapable`.
Allow a list to occur right after a paragraph, with no intervening
blank space.
+#### Extension: `spaced_reference_links` ####
+
+Allow whitespace between the two components of a reference link,
+for example,
+
+ [foo] [bar].
+
#### Extension: `hard_line_breaks` ####
Causes all newlines within a paragraph to be interpreted as hard line
@@ -4059,7 +4101,7 @@ Syntax highlighting
===================
Pandoc will automatically highlight syntax in [fenced code blocks] that
-are marked with a language name. The Haskell library [highlighting-kate] is
+are marked with a language name. The Haskell library [skylighting] is
used for highlighting, which works in HTML, Docx, Ms, and LaTeX/PDF output.
To see a list of language names that pandoc will recognize, type
`pandoc --list-highlight-languages`.
@@ -4072,7 +4114,7 @@ type `pandoc --list-highlight-styles`.
To disable highlighting, use the `--no-highlight` option.
-[highlighting-kate]: https://github.com/jgm/highlighting-kate
+[skylighting]: https://github.com/jgm/skylighting
Custom Styles in Docx Output
============================
@@ -4139,7 +4181,7 @@ which you can modify according to your needs, do
Authors
=======
-© 2006-2016 John MacFarlane (jgm@berkeley.edu). Released under the
+© 2006-2017 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.)
diff --git a/Makefile b/Makefile
index ef68819ef..65cf3146e 100644
--- a/Makefile
+++ b/Makefile
@@ -18,9 +18,15 @@ test:
bench:
stack bench
+weigh:
+ stack build --flag 'pandoc:weigh-pandoc' && stack exec weigh-pandoc
+
reformat:
for f in $(sourcefiles); do echo $$f; stylish-haskell -i $$f ; done
+lint:
+ for f in $(sourcefiles); do echo $$f; hlint --verbose --refactor --refactor-options='-i -s' $$f; done
+
changes_github:
pandoc --filter extract-changes.hs changelog -t markdown_github | sed -e 's/\\#/#/g' | pbcopy
@@ -40,8 +46,8 @@ macospkg: man/pandoc.1
winpkg: pandoc-$(version)-windows.msi
pandoc-$(version)-windows.msi:
- wget 'https://ci.appveyor.com/api/projects/jgm/pandoc/artifacts/windows/pandoc.msi?branch=$(BRANCH)' -O pandoc.msi && \
- osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2017.p12 -in pandoc.msi -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass
+ wget 'https://ci.appveyor.com/api/projects/jgm/pandoc/artifacts/windows/pandoc-windows-i386.msi?branch=$(BRANCH)' -O pandoc.msi && \
+ osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2019.p12 -in pandoc.msi -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass
rm pandoc.msi
man/pandoc.1: MANUAL.txt man/pandoc.1.template
@@ -59,4 +65,4 @@ download_stats:
clean:
stack clean
-.PHONY: deps quick full install clean test bench changes_github macospkg dist prof download_stats reformat
+.PHONY: deps quick full install clean test bench changes_github macospkg dist prof download_stats reformat lint weigh
diff --git a/README.md b/README.md
index 590bddb5b..ebd5ba2e8 100644
--- a/README.md
+++ b/README.md
@@ -140,7 +140,7 @@ new issue.
License
-------
-© 2006-2016 John MacFarlane (jgm@berkeley.edu). Released under the
+© 2006-2017 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.)
diff --git a/appveyor.yml b/appveyor.yml
index 373e1bfe4..2977b4656 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -1,14 +1,31 @@
-clone_folder: "c:\\stack"
+clone_folder: "c:\\pandoc"
environment:
global:
- STACK_ROOT: "c:\\sr"
- STACK_YAML: "c:\\stack\\stack.pkg.yaml"
- WIXBIN: "c:\\Program Files (x86)\\WiX Toolset v3.10\\bin"
+ WIXBIN: "c:\\Program Files (x86)\\WiX Toolset v3.11\\bin"
+ STACK_YAML: "c:\\pandoc\\stack.pkg.yaml"
+ matrix:
+ - STACK_VERSION: "windows-i386"
+ STACK_ROOT: "c:\\sr32"
+ STACK: "%STACK_ROOT%\\stack.exe"
+# - STACK_VERSION: "windows-x86_64"
+# STACK_ROOT: "c:\\sr64"
+# STACK: "%STACK_ROOT%\\stack.exe"
+
+matrix:
+ fast_finish: true
cache:
- - "c:\\sr" # stack root, short paths == fewer problems
- - "c:\\stack\\stack.exe"
- - '%WIXBIN%'
+ - "%STACK_ROOT%"
+ - "%WIXBIN%"
+ # This is where stack install ghc by default, but we don't
+ # cache it because it's too large:
+ # - "c:\\Users\\appveyor\\AppData\\Local\\Programs\\stack"
+
+# Note: to reset build cache, do the following in JavaScript
+# console on appveyor:
+# $.ajax({
+# url: 'https://ci.appveyor.com/api/projects/jgm/pandoc/buildcache',
+# type: 'DELETE'})
# We don't do a normal C build, but build in test_script via stack
build: off
@@ -16,39 +33,35 @@ build: off
install:
- '"%WIXBIN%"\candle -? || choco install wixtoolset'
- |
- stack --version || curl -ostack.zip -L --insecure http://www.stackage.org/stack/windows-i386 && 7z x stack.zip stack.exe
- - stack setup > nul
+ %STACK% --version || curl -ostack.zip -L --insecure http://www.stackage.org/stack/%STACK_VERSION% && 7z e stack.zip -o"%STACK_ROOT%" stack.exe
-before_test:
- # the stack install already fails without the templates...
- - git submodule update --init
- # set PATH to where the hsb2hs binary is copied to
- - cmd: set "PATH=%PATH%;%APPDATA%\\local\\bin"
- - stack install hsb2hs
+# before_test:
test_script:
# The ugly echo "" hack is to avoid complaints about 0 being an invalid file
# descriptor
- - echo "" | stack clean
- - echo "" | stack -j1 --no-terminal test
- - echo "" | stack -j1 --local-bin-path=.\windows install pandoc pandoc-citeproc
+ - |
+ %STACK% setup > nul
+ %STACK% path
+ echo "" | %STACK% clean
+ echo "" | %STACK% -j1 --no-terminal --test --local-bin-path=.\windows install pandoc pandoc-citeproc
after_test:
# .\ in the stack commandline seems to be .\windows\ (where the stack-appveyor.yaml is)
- cd windows
- - 7z a "pandoc.zip" pandoc.exe
- .\pandoc.exe -s --toc ..\MANUAL.txt -o MANUAL.html
- .\pandoc.exe -s ..\COPYING.md -o COPYING.rtf
- copy ..\COPYRIGHT COPYRIGHT.txt
+ - 7z a "pandoc-%STACK_VERSION%.zip" pandoc.exe pandoc-citeproc.exe MANUAL.html COPYING.rtf
- |
set VERSION=
for /f "tokens=1-2 delims= " %%a in ('.\pandoc.exe --version') do ( if not defined VERSION set "VERSION=%%b" )
echo %VERSION%
"%WIXBIN%\\candle" -dVERSION=%VERSION% -dBINPATH=. *.wxs -out wixobj\
- "%WIXBIN%\\light" -sw1076 -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc Pandoc-en-us.wxl -out pandoc.msi wixobj\*.wixobj
+ "%WIXBIN%\\light" -sw1076 -ext WixUIExtension -ext WixUtilExtension -cultures:en-us -loc Pandoc-en-us.wxl -out "pandoc-%STACK_VERSION%.msi" wixobj\*.wixobj
artifacts:
- - path: windows\pandoc.zip
+ - path: 'windows\pandoc-%STACK_VERSION%.zip'
name: exe
- - path: windows\pandoc.msi
+ - path: 'windows\pandoc-%STACK_VERSION%.msi'
name: msi
diff --git a/benchmark/benchmark-pandoc.hs b/benchmark/benchmark-pandoc.hs
index 7294c74a4..2f0242ac4 100644
--- a/benchmark/benchmark-pandoc.hs
+++ b/benchmark/benchmark-pandoc.hs
@@ -17,6 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
import Text.Pandoc
import Text.Pandoc.Class hiding (getCurrentTime)
+import qualified Text.Pandoc.UTF8 as UTF8
+import Data.Text (Text)
import Data.Time (getCurrentTime)
import qualified Data.ByteString as B
import qualified Data.Map as Map
@@ -27,11 +29,11 @@ import Debug.Trace (trace)
import System.Environment (getArgs)
readerBench :: Pandoc
- -> (String, ReaderOptions -> String -> Pandoc)
+ -> (String, ReaderOptions -> Text -> Pandoc)
-> Maybe Benchmark
readerBench doc (name, reader) =
case lookup name writers of
- Just (StringWriter writer) ->
+ Just (TextWriter writer) ->
let inp = either (error . show) id $ runPure
$ writer def{ writerWrapText = WrapAuto} doc
in return $ bench (name ++ " reader") $ nf
@@ -39,7 +41,7 @@ readerBench doc (name, reader) =
_ -> trace ("\nCould not find writer for " ++ name ++ "\n") Nothing
writerBench :: Pandoc
- -> (String, WriterOptions -> Pandoc -> String)
+ -> (String, WriterOptions -> Pandoc -> Text)
-> Benchmark
writerBench doc (name, writer) = bench (name ++ " writer") $ nf
(writer def{ writerWrapText = WrapAuto }) doc
@@ -47,13 +49,13 @@ writerBench doc (name, writer) = bench (name ++ " writer") $ nf
main :: IO ()
main = do
args <- getArgs
- let matchReader (n, StringReader _) =
+ let matchReader (n, TextReader _) =
case args of
[] -> True
[x] -> x == n
(x:y:_) -> x == n && y == "reader"
matchReader (_, _) = False
- let matchWriter (n, StringWriter _) =
+ let matchWriter (n, TextWriter _) =
case args of
[] -> True
[x] -> x == n
@@ -61,7 +63,7 @@ main = do
matchWriter (_, _) = False
let matchedReaders = filter matchReader readers
let matchedWriters = filter matchWriter writers
- inp <- readFile "test/testsuite.txt"
+ inp <- UTF8.toText <$> B.readFile "test/testsuite.txt"
lalune <- B.readFile "test/lalune.jpg"
movie <- B.readFile "test/movie.jpg"
time <- getCurrentTime
@@ -74,12 +76,12 @@ main = do
let doc = either (error . show) id $ runPure $ readMarkdown opts inp
let readers' = [(n, \o d ->
either (error . show) id $ runPure $ r o d)
- | (n, StringReader r) <- matchedReaders]
+ | (n, TextReader r) <- matchedReaders]
let readerBs = mapMaybe (readerBench doc)
$ filter (\(n,_) -> n /="haddock") readers'
let writers' = [(n, \o d ->
either (error . show) id $ runPure $ setupFakeFiles >> w o d)
- | (n, StringWriter w) <- matchedWriters]
+ | (n, TextWriter w) <- matchedWriters]
let writerBs = map (writerBench doc)
$ writers'
defaultMainWith defaultConfig{ timeLimit = 6.0 }
diff --git a/benchmark/weigh-pandoc.hs b/benchmark/weigh-pandoc.hs
index b4462d747..d3cada8c0 100644
--- a/benchmark/weigh-pandoc.hs
+++ b/benchmark/weigh-pandoc.hs
@@ -1,5 +1,6 @@
import Weigh
import Text.Pandoc
+import Data.Text (Text)
main :: IO ()
main = do
@@ -23,13 +24,13 @@ main = do
,("commonmark", writeCommonMark)
]
-weighWriter :: Pandoc -> String -> (Pandoc -> String) -> Weigh ()
+weighWriter :: Pandoc -> String -> (Pandoc -> Text) -> Weigh ()
weighWriter doc name writer = func (name ++ " writer") writer doc
-weighReader :: Pandoc -> String -> (String -> Pandoc) -> Weigh ()
+weighReader :: Pandoc -> String -> (Text -> Pandoc) -> Weigh ()
weighReader doc name reader = do
case lookup name writers of
- Just (StringWriter writer) ->
+ Just (TextWriter writer) ->
let inp = either (error . show) id $ runPure $ writer def{ writerWrapText = WrapAuto} doc
in func (name ++ " reader") reader inp
_ -> return () -- no writer for reader
diff --git a/data/docx/word/styles.xml b/data/docx/word/styles.xml
index 5d09a67b0..3596d8bbc 100644
--- a/data/docx/word/styles.xml
+++ b/data/docx/word/styles.xml
@@ -342,8 +342,9 @@
<w:semiHidden />
<w:unhideWhenUsed />
</w:style>
- <w:style w:type="table" w:default="1" w:styleId="TableNormal">
- <w:name w:val="Normal Table" />
+ <w:style w:type="table" w:default="1" w:styleId="Table">
+ <w:name w:val="Table" />
+ <w:basedOn w:val="TableNormal" />
<w:semiHidden />
<w:unhideWhenUsed />
<w:qFormat />
@@ -400,8 +401,8 @@
<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:style w:type="paragraph" w:customStyle="1" w:styleId="CaptionedFigure">
+ <w:name w:val="Captioned Figure" />
<w:basedOn w:val="Figure" />
<w:pPr>
<w:keepNext />
diff --git a/data/pandoc.lua b/data/pandoc.lua
index 2a5a945b5..750b41e86 100644
--- a/data/pandoc.lua
+++ b/data/pandoc.lua
@@ -233,11 +233,11 @@ M.BulletList = M.Block:create_constructor(
--- Creates a code block element
-- @function CodeBlock
-- @tparam string text code string
--- @tparam[opt] Attr attributes element attributes
+-- @tparam[opt] Attr attr element attributes
-- @treturn Block code block element
M.CodeBlock = M.Block:create_constructor(
"CodeBlock",
- function(text, attributes) return {c = {attributes, text}} end,
+ function(text, attr) return {c = {attr or M.Attr(), text}} end,
{{"identifier", "classes", "attributes"}, "text"}
)
@@ -254,11 +254,13 @@ M.DefinitionList = M.Block:create_constructor(
--- Creates a div element
-- @function Div
-- @tparam {Block,...} content block content
--- @tparam[opt] Attr attributes element attributes
+-- @tparam[opt] Attr attr element attributes
-- @treturn Block code block element
M.Div = M.Block:create_constructor(
"Div",
- function(content, attributes) return {c = {attributes, content}} end,
+ function(content, attr)
+ return {c = {attr or M.Attr(), content}}
+ end,
{{"identifier", "classes", "attributes"}, "content"}
)
@@ -266,12 +268,12 @@ M.Div = M.Block:create_constructor(
-- @function Header
-- @tparam int level header level
-- @tparam {Inline,...} content inline content
--- @tparam Attr attributes element attributes
+-- @tparam[opt] Attr attr element attributes
-- @treturn Block header element
M.Header = M.Block:create_constructor(
"Header",
- function(level, content, attributes)
- return {c = {level, attributes, content}}
+ function(level, content, attr)
+ return {c = {level, attr or M.Attr(), content}}
end,
{"level", {"identifier", "classes", "attributes"}, "content"}
)
@@ -386,11 +388,11 @@ M.Cite = M.Inline:create_constructor(
--- Creates a Code inline element
-- @function Code
-- @tparam string text brief image description
--- @tparam[opt] Attr attributes additional attributes
+-- @tparam[opt] Attr attr additional attributes
-- @treturn Inline code element
M.Code = M.Inline:create_constructor(
"Code",
- function(text, attributes) return {c = {attributes, text}} end,
+ function(text, attr) return {c = {attr or M.Attr(), text}} end,
{{"identifier", "classes", "attributes"}, "text"}
)
@@ -409,14 +411,14 @@ M.Emph = M.Inline:create_constructor(
-- @tparam {Inline,..} caption text used to describe the image
-- @tparam string src path to the image file
-- @tparam[opt] string title brief image description
--- @tparam[opt] Attr attributes additional attributes
+-- @tparam[opt] Attr attr additional attributes
-- @treturn Inline image element
M.Image = M.Inline:create_constructor(
"Image",
- function(caption, src, title, attributes)
+ function(caption, src, title, attr)
title = title or ""
- attributes = attributes or Attribute.empty
- return {c = {attributes, caption, {src, title}}}
+ attr = attr or M.Attr()
+ return {c = {attr, caption, {src, title}}}
end,
{"attributes", "caption", {"src", "title"}}
)
@@ -434,14 +436,14 @@ M.LineBreak = M.Inline:create_constructor(
-- @tparam {Inline,..} content text for this link
-- @tparam string target the link target
-- @tparam[opt] string title brief link description
--- @tparam[opt] Attr attributes additional attributes
+-- @tparam[opt] Attr attr additional attributes
-- @treturn Inline image element
M.Link = M.Inline:create_constructor(
"Link",
- function(content, target, title, attributes)
+ function(content, target, title, attr)
title = title or ""
- attributes = attributes or Attribute.empty
- return {c = {attributes, content, {target, title}}}
+ attr = attr or M.Attr()
+ return {c = {attr, content, {target, title}}}
end,
{"attributes", "content", {"target", "title"}}
)
@@ -560,11 +562,11 @@ M.Space = M.Inline:create_constructor(
--- Creates a Span inline element
-- @function Span
-- @tparam {Inline,..} content inline content
--- @tparam[opt] Attr attributes additional attributes
+-- @tparam[opt] Attr attr additional attributes
-- @treturn Inline span element
M.Span = M.Inline:create_constructor(
"Span",
- function(content, attributes) return {c = {attributes, content}} end,
+ function(content, attr) return {c = {attr or M.Attr(), content}} end,
{{"identifier", "classes", "attributes"}, "content"}
)
diff --git a/data/templates/default.beamer b/data/templates/default.beamer
index fb02cb058..c9d30b657 100644
--- a/data/templates/default.beamer
+++ b/data/templates/default.beamer
@@ -1,4 +1,4 @@
-\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(handout)$handout,$endif$$if(colorlinks)$dvipsnames,$endif$$if(beamer)$ignorenonframetext,$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
+\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(handout)$handout,$endif$$if(colorlinks)$dvipsnames,$endif$$if(beamer)$ignorenonframetext,$endif$$for(classoption)$$classoption$$sep$,$endfor$$if(aspectratio)$aspectratio=$aspectratio$,$endif$]{$documentclass$}
\setbeamertemplate{caption}[numbered]
\setbeamertemplate{caption label separator}{: }
\setbeamercolor{caption name}{fg=normal text.fg}
diff --git a/data/templates/default.context b/data/templates/default.context
index 4a3457934..e17d85b36 100644
--- a/data/templates/default.context
+++ b/data/templates/default.context
@@ -23,6 +23,7 @@ $endif$
style=$linkstyle$,
color=$linkcolor$,
contrastcolor=$linkcontrastcolor$]
+
% make chapter, section bookmarks visible when opening document
\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
\setupinteractionscreen[option=bookmark]
@@ -37,26 +38,22 @@ $endif$
$if(pagenumbering)$
\setuppagenumbering[$for(pagenumbering)$$pagenumbering$$sep$,$endfor$]
$endif$
+
% use microtypography
\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
\setupalign[hz,hanging]
\setupitaliccorrection[global, always]
+
\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts$if(fontsize)$,$fontsize$$endif$]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
-$if(mainfont)$
-\setmainfont[$mainfont$]
-$endif$
-$if(sansfont)$
-\setsansfont[$sansfont$][rscale=auto]
-$endif$
-$if(monofont)$
-\setmonofont[$monofont$][features=none, rscale=auto]
-$endif$
-$if(mathfont)$
-\setmathfont[$mathfont$][rscale=auto]
-$endif$
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][$if(mainfont)$$mainfont$$else$Latin Modern Roman$endif$]
+\definefontfamily[mainface][mm][$if(mathfont)$$mathfont$$else$Latin Modern Math$endif$]
+\definefontfamily[mainface][ss][$if(sansfont)$$sansfont$$else$Latin Modern Sans$endif$]
+\definefontfamily[mainface][tt][$if(monofont)$$monofont$$else$Latin Modern Typewriter$endif$][features=none]
+\setupbodyfont[mainface$if(fontsize)$,$fontsize$$endif$]
+
\setupwhitespace[$if(whitespace)$$whitespace$$else$medium$endif$]
$if(indenting)$
\setupindenting[$for(indenting)$$indenting$$sep$,$endfor$]
diff --git a/data/templates/default.latex b/data/templates/default.latex
index 899a00aea..156c43985 100644
--- a/data/templates/default.latex
+++ b/data/templates/default.latex
@@ -69,6 +69,15 @@ $endif$
\usepackage[$for(microtypeoptions)$$microtypeoptions$$sep$,$endfor$]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+$if(indent)$
+$else$
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
+$endif$
\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
$if(verbatim-in-note)$
\usepackage{fancyvrb}
@@ -103,20 +112,6 @@ $endif$
$if(geometry)$
\usepackage[$for(geometry)$$geometry$$sep$,$endfor$]{geometry}
$endif$
-$if(lang)$
-\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
- \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
-$if(babel-newcommands)$
- $babel-newcommands$
-$endif$
-\else
- \usepackage{polyglossia}
- \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
-$for(polyglossia-otherlangs)$
- \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
-$endfor$
-\fi
-$endif$
$if(natbib)$
\usepackage{natbib}
\bibliographystyle{$if(biblio-style)$$biblio-style$$else$plainnat$endif$}
@@ -155,22 +150,13 @@ $if(graphics)$
$endif$
$if(links-as-notes)$
% Make links footnotes instead of hotlinks:
-\renewcommand{\href}[2]{#2\footnote{\url{#1}}}
+\DeclareRobustCommand{\href}[2]{#2\footnote{\url{#1}}}
$endif$
$if(strikeout)$
\usepackage[normalem]{ulem}
% avoid problems with \sout in headers with hyperref:
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
$endif$
-$if(indent)$
-$else$
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
-$endif$
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
@@ -191,6 +177,21 @@ $else$
\renewcommand{\subparagraph}[1]{\oldsubparagraph{#1}\mbox{}}
\fi
$endif$
+$if(lang)$
+\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
+ \usepackage[shorthands=off,$for(babel-otherlangs)$$babel-otherlangs$,$endfor$main=$babel-lang$]{babel}
+$if(babel-newcommands)$
+ $babel-newcommands$
+$endif$
+\else
+ % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
+ \usepackage{polyglossia}
+ \setmainlanguage[$polyglossia-lang.options$]{$polyglossia-lang.name$}
+$for(polyglossia-otherlangs)$
+ \setotherlanguage[$polyglossia-otherlangs.options$]{$polyglossia-otherlangs.name$}
+$endfor$
+\fi
+$endif$
$if(dir)$
\ifxetex
% load bidi as late as possible as it modifies e.g. graphicx
diff --git a/linux/control.in b/linux/control.in
index d1aa865ce..7653fa823 100644
--- a/linux/control.in
+++ b/linux/control.in
@@ -5,16 +5,20 @@ Priority: optional
Architecture: ARCHITECTURE
Installed-Size: INSTALLED_SIZE
Depends: libc6 (>= 2.13), libgmp10, zlib1g (>= 1:1.1.4)
+Suggests: texlive-latex-recommended, texlive-xetex,
+ texlive-fonts-recommended
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, Muse, and several kinds of HTML/javascript
- slide shows (S5, Slidy, Slideous, DZSlides, reveal.js).
+ this library. It can read several dialects of Markdown and
+ (subsets of) HTML, reStructuredText, LaTeX, DocBook, MediaWiki
+ markup, Word docx, ODT, EPUB, TWiki markup, Haddock markup, OPML,
+ Emacs Org-Mode, txt2tags and Textile, and it can write Markdown,
+ reStructuredText, HTML, LaTeX, ConTeXt, DocBook, OPML, GNU TexInfo,
+ OpenDocument, ODT, Word docx, RTF, MediaWiki, ZimWiki,
+ DokuWiki, Textile, groff man pages, groff ms, plain text,
+ Emacs Org-Mode, AsciiDoc, Haddock markup, EPUB (v2 and v3),
+ FictionBook2, InDesign ICML, TEI Simple, JATS XML, Muse,
+ and several kinds of HTML/javascript slide shows (S5, Slidy,
+ Slideous, DZSlides, reveal.js).
diff --git a/macos/make_macos_package.sh b/macos/make_macos_package.sh
index c5d073cdc..f49b6a81b 100755
--- a/macos/make_macos_package.sh
+++ b/macos/make_macos_package.sh
@@ -7,6 +7,7 @@ VERSION=$(grep -e '^Version' pandoc.cabal | awk '{print $2}')
RESOURCES=$DIST/Resources
ROOT=$DIST/pandoc
DEST=$ROOT/usr/local
+PANDOC=$DEST/bin/pandoc
SCRIPTS=$MACOS/macos-resources
BASE=pandoc-$VERSION
ME=$(whoami)
@@ -20,12 +21,14 @@ export MACMACOS_DEPLOYMENT_TARGET=10.7
rm -rf $DIST
mkdir -p $DIST
mkdir -p $RESOURCES
+mkdir -p $DEST/bin
+mkdir -p $DEST/share/man/man1
+
stack setup
-which cpphs || stack install cpphs
echo Building pandoc...
stack clean
-stack install --stack-yaml=stack.pkg.yaml --local-bin-path . pandoc pandoc-citeproc
+stack install --stack-yaml=stack.pkg.yaml --local-bin-path $DEST/bin/ pandoc pandoc-citeproc
echo Getting man pages...
make man/pandoc.1
@@ -36,18 +39,13 @@ PANDOC_CITEPROC_TARBALL=https://hackage.haskell.org/package/pandoc-citeproc-${PA
curl ${PANDOC_CITEPROC_TARBALL} | tar xzC $DIST
PANDOC_CITEPROC_PATH=$DIST/pandoc-citeproc-${PANDOC_CITEPROC_VERSION}
-mkdir -p $DEST/bin
-mkdir -p $DEST/share/man/man1
-for f in pandoc pandoc-citeproc; do
- cp $MACOS/$f $DEST/bin/;
-done
cp $PANDOC_CITEPROC_PATH/man/man1/pandoc-citeproc.1 $DEST/share/man/man1/
cp man/pandoc.1 $DEST/share/man/man1/
chown -R $ME:staff $DIST
echo Copying license...
-$MACOS/pandoc --data data -t html5 -s COPYING.md -o $RESOURCES/license.html
+$PANDOC --data data -t html5 -s COPYING.md -Vpagetitle="License" -o $RESOURCES/license.html
# Removing executable signing because of a problem that arose in El Capitan
# "source=obsolete resource envelope"
@@ -62,11 +60,11 @@ echo Creating MacOS package...
sed -e "s/PANDOCVERSION/$VERSION/" $MACOS/distribution.xml.in > $MACOS/distribution.xml
-pkgbuild --root $DIST/pandoc --identifier net.johnmacfarlane.pandoc --version 1.13 --ownership recommended $DIST/pandoc.pkg
+pkgbuild --root $ROOT --identifier net.johnmacfarlane.pandoc --version $VERSION --ownership recommended $DIST/pandoc.pkg
productbuild --distribution $MACOS/distribution.xml --resources $DIST/Resources --package-path $DIST --version $VERSION --sign "${DEVELOPER_ID_INSTALLER}" $BASE-MacOS.pkg
# verify signature
spctl --assess --type install $BASE-MacOS.pkg
# cleanup
-rm -r $DIST $MACOS/pandoc $MACOS/pandoc-citeproc
+rm -r $DIST
diff --git a/man/pandoc.1 b/man/pandoc.1
index a9cb65854..15dbcbe07 100644
--- a/man/pandoc.1
+++ b/man/pandoc.1
@@ -1,5 +1,5 @@
.\"t
-.TH PANDOC 1 "January 29, 2017" "pandoc 1.19.2"
+.TH PANDOC 1 "March 26, 2017" "pandoc 2.0"
.SH NAME
pandoc - general markup converter
.SH SYNOPSIS
@@ -18,10 +18,11 @@ Markdown, MultiMarkdown, reStructuredText, XHTML, HTML5, LaTeX
(including \f[C]beamer\f[] slide shows), ConTeXt, RTF, OPML, DocBook,
OpenDocument, ODT, Word docx, GNU Texinfo, MediaWiki markup, DokuWiki
markup, ZimWiki markup, Haddock markup, EPUB (v2 or v3), FictionBook2,
-Textile, groff man pages, Emacs Org mode, AsciiDoc, InDesign ICML, TEI
-Simple, and Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide shows.
-It can also produce PDF output on systems where LaTeX, ConTeXt, or
-\f[C]wkhtmltopdf\f[] is installed.
+Textile, groff man, groff ms, Emacs Org mode, AsciiDoc, InDesign ICML,
+TEI Simple, and Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide
+shows.
+It can also produce PDF output on systems where LaTeX, ConTeXt,
+\f[C]pdfroff\f[], or \f[C]wkhtmltopdf\f[] is installed.
.PP
Pandoc's enhanced version of Markdown includes syntax for footnotes,
tables, flexible ordered lists, definition lists, fenced code blocks,
@@ -57,7 +58,7 @@ 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).
+\f[C]epub2\f[], and \f[C]epub3\f[] output formats).
For output to a file, use the \f[C]\-o\f[] option:
.IP
.nf
@@ -89,6 +90,15 @@ pandoc\ \-f\ html\ \-t\ markdown\ http://www.fsf.org
\f[]
.fi
.PP
+It is possible to supply a custom User\-Agent string when requesting a
+document from a URL, by setting an environment variable:
+.IP
+.nf
+\f[C]
+USER_AGENT="Mozilla/5.0"\ 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[],
@@ -172,29 +182,32 @@ pandoc\ test.txt\ \-o\ test.pdf
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]amsfonts\f[], \f[C]amsmath\f[],
-\f[C]lm\f[], \f[C]ifxetex\f[], \f[C]ifluatex\f[], \f[C]eurosym\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]graphicx\f[] and \f[C]grffile\f[] (if the document contains
-images), \f[C]hyperref\f[], \f[C]ulem\f[], \f[C]geometry\f[] (with the
-\f[C]geometry\f[] variable set), \f[C]setspace\f[] (with
-\f[C]linestretch\f[]), and \f[C]babel\f[] (with \f[C]lang\f[]).
+\f[C]lm\f[], \f[C]unicode\-math\f[], \f[C]ifxetex\f[],
+\f[C]ifluatex\f[], \f[C]eurosym\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]graphicx\f[] and
+\f[C]grffile\f[] (if the document contains images), \f[C]hyperref\f[],
+\f[C]ulem\f[], \f[C]geometry\f[] (with the \f[C]geometry\f[] variable
+set), \f[C]setspace\f[] (with \f[C]linestretch\f[]), and \f[C]babel\f[]
+(with \f[C]lang\f[]).
The use of \f[C]xelatex\f[] or \f[C]lualatex\f[] as the LaTeX engine
-requires \f[C]fontspec\f[]; \f[C]xelatex\f[] uses \f[C]mathspec\f[],
-\f[C]polyglossia\f[] (with \f[C]lang\f[]), \f[C]xecjk\f[], and
-\f[C]bidi\f[] (with the \f[C]dir\f[] variable set).
+requires \f[C]fontspec\f[].
+\f[C]xelatex\f[] uses \f[C]polyglossia\f[] (with \f[C]lang\f[]),
+\f[C]xecjk\f[], and \f[C]bidi\f[] (with the \f[C]dir\f[] variable set).
+If the \f[C]mathspec\f[] variable is set, \f[C]xelatex\f[] will use
+\f[C]mathspec\f[] instead of \f[C]unicode\-math\f[].
The \f[C]upquote\f[] and \f[C]microtype\f[] packages are used if
-available, and \f[C]csquotes\f[] will be used for smart punctuation if
+available, and \f[C]csquotes\f[] will be used for [smart punctuation] if
added to the template or included in any header file.
The \f[C]natbib\f[], \f[C]biblatex\f[], \f[C]bibtex\f[], and
\f[C]biber\f[] packages can optionally be used for citation rendering.
These are included with all recent versions of TeX Live.
.PP
-Alternatively, pandoc can use ConTeXt or \f[C]wkhtmltopdf\f[] to create
-a PDF.
+Alternatively, pandoc can use ConTeXt, \f[C]wkhtmltopdf\f[], or
+\f[C]pdfroff\f[] to create a PDF.
To do this, specify an output file with a \f[C]\&.pdf\f[] extension, as
-before, but add \f[C]\-t\ context\f[] or \f[C]\-t\ html5\f[] to the
-command line.
+before, but add \f[C]\-t\ context\f[], \f[C]\-t\ html5\f[], or
+\f[C]\-t\ ms\f[] to the command line.
.PP
PDF output can be controlled using variables for LaTeX (if LaTeX is
used) and variables for ConTeXt (if ConTeXt is used).
@@ -243,18 +256,20 @@ Specify output format.
(original unextended Markdown), \f[C]markdown_phpextra\f[] (PHP Markdown
Extra), \f[C]markdown_github\f[] (GitHub\-Flavored Markdown),
\f[C]markdown_mmd\f[] (MultiMarkdown), \f[C]commonmark\f[] (CommonMark
-Markdown), \f[C]rst\f[] (reStructuredText), \f[C]html\f[] (XHTML),
-\f[C]html5\f[] (HTML5), \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
+Markdown), \f[C]rst\f[] (reStructuredText), \f[C]html4\f[] (XHTML 1.0
+Transitional), \f[C]html\f[] or \f[C]html5\f[] (HTML5/XHTML polyglot
+markup), \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]zimwiki\f[] (ZimWiki 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 4), \f[C]docbook5\f[]
-(DocBook 5), \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]opml\f[] (OPML), \f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4),
+\f[C]docbook5\f[] (DocBook 5), \f[C]jats\f[] (JATS XML),
+\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]epub2\f[] (EPUB v2 book),
+\f[C]epub\f[] or \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]tei\f[] (TEI Simple), \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),
@@ -265,7 +280,7 @@ 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
+\f[C]latex\f[], \f[C]beamer\f[], \f[C]html4\f[], or \f[C]html5\f[], the
output will be rendered as literate Haskell source: see Literate Haskell
support, below.
Markdown syntax extensions can be individually enabled or disabled by
@@ -340,6 +355,23 @@ Currently this only has an effect with PDF output.
.RS
.RE
.TP
+.B \f[C]\-\-quiet\f[]
+Suppress warning messages.
+.RS
+.RE
+.TP
+.B \f[C]\-\-fail\-if\-warnings\f[]
+Exit with error status if there are any warnings.
+.RS
+.RE
+.TP
+.B \f[C]\-\-log=\f[]\f[I]FILE\f[]
+Write log messages in machine\-readable JSON format to \f[I]FILE\f[].
+All messages above DEBUG level will be written, regardless of verbosity
+settings (\f[C]\-\-verbose\f[], \f[C]\-\-quiet\f[]).
+.RS
+.RE
+.TP
.B \f[C]\-\-list\-input\-formats\f[]
List supported input formats, one per line.
.RS
@@ -379,41 +411,6 @@ Show usage message.
.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, Emacs Org mode,
-HTML, Slidy, Slideous, DZSlides, reveal.js, and S5 output; raw LaTeX can
-be printed in Markdown, reStructuredText, Emacs Org mode, 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
-\[lq]Mr.\[rq] (Note: This option is selected automatically when the
-output format is \f[C]latex\f[] or \f[C]context\f[], unless
-\f[C]\-\-no\-tex\-ligatures\f[] is used.
-It has no effect for \f[C]latex\f[] input.)
-.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
@@ -487,6 +484,37 @@ a specified full or relative path (executable or non\-executable)
\f[C]$PATH\f[] (executable only)
.RE
.TP
+.B \f[C]\-\-lua\-filter=\f[]\f[I]SCRIPT\f[]
+Transform the document in a similar fashion as JSON filters (see
+\f[C]\-\-filter\f[]), but use pandoc's build\-in lua filtering system.
+The given lua script is expected to return a list of lua filters which
+will be applied in order.
+Each lua filter must contain element\-transforming functions indexed by
+the name of the AST element on which the filter function should be
+applied.
+.RS
+.PP
+The \f[C]pandoc\f[] lua module provides helper functions for element
+creation.
+It is always loaded into the script's lua environment.
+.PP
+The following is an example lua script for macro\-expansion:
+.IP
+.nf
+\f[C]
+function\ expand_hello_world(inline)
+\ \ if\ inline.c\ ==\ \[aq]{{helloworld}}\[aq]\ then
+\ \ \ \ return\ pandoc.Emph{\ pandoc.Str\ "Hello,\ World"\ }
+\ \ else
+\ \ \ \ return\ inline
+\ \ end
+end
+
+return\ {{Str\ =\ expand_hello_world}}
+\f[]
+.fi
+.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
@@ -501,13 +529,6 @@ 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
@@ -539,10 +560,29 @@ This option only affects the docx reader.
.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.
+Extract images and other media contained in or linked from the source
+document 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.
+If the source format is a binary container (docx, epub, or odt), the
+media is extracted from the container and the original filenames are
+used.
+Otherwise the media is read from the file system or downloaded, and new
+filenames are constructed based on SHA1 hashes of the contents.
+.RS
+.RE
+.TP
+.B \f[C]\-\-abbreviations=\f[]\f[I]FILE\f[]
+Specifies a custom abbreviations file, with abbreviations one to a line.
+If this option is not specified, pandoc will read the data file
+\f[C]abbreviations\f[] from the user data directory or fall back on a
+system default.
+To see the system default, use
+\f[C]pandoc\ \-\-print\-default\-data\-file=abbreviations\f[].
+The only use pandoc makes of this list is in the Markdown reader.
+Strings ending in a period that are found in this list will be followed
+by a nonbreaking space, so that the period will not produce
+sentence\-ending space in formats like LaTeX.
.RS
.RE
.SS General writer options
@@ -595,6 +635,14 @@ Files in the user data directory are ignored.
.RS
.RE
.TP
+.B \f[C]\-\-eol=crlf\f[]|\f[C]lf\f[]|\f[C]native\f[]
+Manually specify line endings: \f[C]crlf\f[] (Windows), \f[C]lf\f[]
+(MacOS/linux/unix), or \f[C]native\f[] (line endings appropriate to the
+OS on which pandoc is being run).
+The default is \f[C]native\f[].
+.RS
+.RE
+.TP
.B \f[C]\-\-dpi\f[]=\f[I]NUMBER\f[]
Specify the dpi (dots per inch) value for conversion from pixels to
inch/centimeters and vice versa.
@@ -617,11 +665,6 @@ Automatic wrapping does not currently work in HTML output.
.RS
.RE
.TP
-.B \f[C]\-\-no\-wrap\f[]
-Deprecated synonym for \f[C]\-\-wrap=none\f[].
-.RS
-.RE
-.TP
.B \f[C]\-\-columns=\f[]\f[I]NUMBER\f[]
Specify length of lines in characters.
This affects text wrapping in the generated source code (see
@@ -633,11 +676,11 @@ Tables below).
.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[], \f[C]docx\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]docbook5\f[], \f[C]slidy\f[], \f[C]slideous\f[], \f[C]s5\f[], or
-\f[C]odt\f[] output.
+\f[C]latex\f[], \f[C]context\f[], \f[C]docx\f[], \f[C]rst\f[], or
+\f[C]ms\f[], an instruction to create one) in the output document.
+This option has no effect on \f[C]man\f[], \f[C]docbook4\f[],
+\f[C]docbook5\f[], \f[C]jats\f[], \f[C]slidy\f[], \f[C]slideous\f[],
+\f[C]s5\f[], or \f[C]odt\f[] output.
.RS
.RE
.TP
@@ -655,7 +698,7 @@ language attribute is given.
.RS
.RE
.TP
-.B \f[C]\-\-highlight\-style=\f[]\f[I]STYLE\f[]
+.B \f[C]\-\-highlight\-style=\f[]\f[I]STYLE\f[]|\f[I]FILE\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]breezeDark\f[], \f[C]espresso\f[],
@@ -664,6 +707,21 @@ For more information on syntax highlighting in pandoc, see Syntax
highlighting, below.
See also \f[C]\-\-list\-highlight\-styles\f[].
.RS
+.PP
+Instead of a \f[I]STYLE\f[] name, a JSON file with extension
+\f[C]\&.theme\f[] may be supplied.
+This will be parsed as a KDE syntax highlighting theme and (if valid)
+used as the highlighting style.
+To see a sample theme that can be modified,
+\f[C]pandoc\ \-\-print\-default\-data\-file\ default.theme\f[].
+.RE
+.TP
+.B \f[C]\-\-syntax\-definition=\f[]\f[I]FILE\f[]
+Instructs pandoc to load a KDE XML syntax definition file, which will be
+used for syntax highlighting of appropriately marked code blocks.
+This can be used to add support for new languages or to use altered
+syntax definitions for existing languages.
+.RS
.RE
.TP
.B \f[C]\-H\f[] \f[I]FILE\f[], \f[C]\-\-include\-in\-header=\f[]\f[I]FILE\f[]
@@ -698,6 +756,19 @@ They will be included in the order specified.
Implies \f[C]\-\-standalone\f[].
.RS
.RE
+.TP
+.B \f[C]\-\-resource\-path=\f[]\f[I]SEARCHPATH\f[]
+List of paths to search for images and other resources.
+The paths should be separated by \f[C]:\f[] on linux, unix, and MacOS
+systems, and by \f[C];\f[] on Windows.
+If \f[C]\-\-resource\-path\f[] is not specified, the default resource
+path is the working directory.
+Note that, if \f[C]\-\-resource\-path\f[] is specified, the working
+directory must be explicitly listed or it will not be searched.
+For example: \f[C]\-\-resource\-path=.:test\f[] will search the working
+directory and the \f[C]test\f[] subdirectory, in that order.
+.RS
+.RE
.SS Options affecting specific writers
.TP
.B \f[C]\-\-self\-contained\f[]
@@ -708,13 +779,16 @@ The resulting file should be \[lq]self\-contained,\[rq] 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]html4\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).
+Elements with the attribute \f[C]data\-external="1"\f[] will be left
+alone; the documents they link to will not be incorporated in the
+document.
Limitation: resources that are loaded dynamically through JavaScript
cannot be incorporated; as a result, \f[C]\-\-self\-contained\f[] does
not work with \f[C]\-\-mathjax\f[], and some advanced features
@@ -730,8 +804,8 @@ Use \f[C]<q>\f[] tags for quotes in HTML.
.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).
+Currently supported only for HTML and DocBook output (which uses
+numerical entities instead of UTF\-8 when this option is selected).
.RS
.RE
.TP
@@ -760,11 +834,6 @@ ATX headers.
.RS
.RE
.TP
-.B \f[C]\-\-chapters\f[]
-Deprecated synonym for \f[C]\-\-top\-level\-division=chapter\f[].
-.RS
-.RE
-.TP
.B \f[C]\-\-top\-level\-division=[default|section|chapter|part]\f[]
Treat top\-level headers as the given division type in LaTeX, ConTeXt,
DocBook, and TEI output.
@@ -805,25 +874,6 @@ Implies \f[C]\-\-number\-sections\f[].
.RS
.RE
.TP
-.B \f[C]\-\-no\-tex\-ligatures\f[]
-Do not use the TeX ligatures for quotation marks, apostrophes, and
-dashes (\f[C]`...\[aq]\f[], \f[C]``..\[aq]\[aq]\f[], \f[C]\-\-\f[],
-\f[C]\-\-\-\f[]) when writing or reading LaTeX or ConTeXt.
-In reading LaTeX, parse the characters \f[C]`\f[], \f[C]\[aq]\f[], and
-\f[C]\-\f[] literally, rather than parsing ligatures for quotation marks
-and dashes.
-In writing LaTeX or ConTeXt, print unicode quotation mark and dash
-characters literally, rather than converting them to the standard ASCII
-TeX ligatures.
-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 the \f[C]listings\f[] package for LaTeX code blocks
.RS
@@ -842,6 +892,8 @@ Specifies that headers with the specified level create slides (for
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.
+Note that content that is not contained under slide\-level headers will
+not appear in the slide show.
The default is to set the slide level based on the contents of the
document; see Structuring the slide show.
.RS
@@ -867,8 +919,9 @@ The default is \f[C]none\f[].
.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.
+Specify a prefix to be added to all identifiers and internal links in
+HTML and DocBook output, and to footnote numbers in Markdown and Haddock
+output.
This is useful for preventing duplicate identifiers when generating
fragments to be included in other pages.
.RS
@@ -887,29 +940,20 @@ Link to a CSS style sheet.
This option can be used repeatedly to include multiple files.
They will be included in the order specified.
.RS
+.PP
+A stylesheet is required for generating EPUB.
+If none is provided using this option (or the \f[C]stylesheet\f[]
+metadata field), 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.
.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.
+.B \f[C]\-\-reference\-doc=\f[]\f[I]FILE\f[]
+Use the specified file as a style reference in producing a docx or ODT
+file.
.RS
-.PP
-To produce a custom \f[C]reference.odt\f[], first get a copy of the
-default \f[C]reference.odt\f[]:
-\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.odt\ >\ custom\-reference.odt\f[].
-Then open \f[C]custom\-reference.docx\f[] in LibreOffice, modify the
-styles as you wish, and save the file.
-.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.
+.B Docx
For best results, the reference docx should be a modified version of a
docx file produced using pandoc.
The contents of the reference docx are ignored, but its stylesheets and
@@ -930,19 +974,30 @@ For best results, do not make changes to this file other than modifying
the styles 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.
+Heading 6, Heading 7, Heading 8, Heading 9, Block Text, Footnote Text,
+Definition Term, Definition, Caption, Table Caption, Image Caption,
+Figure, Captioned Figure, TOC Heading; [character] Default Paragraph
+Font, Body Text Char, Verbatim Char, Footnote Reference, Hyperlink;
+[table] Table.
.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
+.B 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 it is not found there, sensible defaults will be used.
+If this is not found either, sensible defaults will be used.
.RS
+.PP
+To produce a custom \f[C]reference.odt\f[], first get a copy of the
+default \f[C]reference.odt\f[]:
+\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.odt\ >\ custom\-reference.odt\f[].
+Then open \f[C]custom\-reference.odt\f[] in LibreOffice, modify the
+styles as you wish, and save the file.
+.RE
.RE
.TP
.B \f[C]\-\-epub\-cover\-image=\f[]\f[I]FILE\f[]
@@ -989,7 +1044,7 @@ 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[]):
+following to your CSS (see \f[C]\-\-css\f[]):
.RS
.IP
.nf
@@ -1115,12 +1170,9 @@ 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[], \f[C]docbook5\f[],
-\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.
+.B \f[C]\-\-mathml\f[]
+Convert TeX math to MathML (in \f[C]docbook4\f[], \f[C]docbook5\f[],
+\f[C]jats\f[], \f[C]html4\f[] and \f[C]html5\f[]).
.RS
.RE
.TP
@@ -1252,7 +1304,7 @@ For \f[C]pdf\f[] output, customize the \f[C]default.latex\f[] template
use \f[C]\-t\ context\f[]).
.IP \[bu] 2
\f[C]docx\f[] has no template (however, you can use
-\f[C]\-\-reference\-docx\f[] to customize the output).
+\f[C]\-\-reference\-doc\f[] to customize the output).
.PP
Templates contain \f[I]variables\f[], which allow for the inclusion of
arbitrary information at any point in the file.
@@ -1266,6 +1318,29 @@ Some variables are set automatically by pandoc.
These vary somewhat depending on the output format, but include metadata
fields as well as the following:
.TP
+.B \f[C]sourcefile\f[], \f[C]outputfile\f[]
+source and destination filenames, as given on the command line.
+\f[C]sourcefile\f[] can also be a list if input comes from multiple
+files, or empty if input is from stdin.
+You can use the following snippet in your template to distinguish them:
+.RS
+.IP
+.nf
+\f[C]
+$if(sourcefile)$
+$for(sourcefile)$
+$sourcefile$
+$endfor$
+$else$
+(stdin)
+$endif$
+\f[]
+.fi
+.PP
+Similarly, \f[C]outputfile\f[] can be \f[C]\-\f[] if output goes to the
+terminal.
+.RE
+.TP
.B \f[C]title\f[], \f[C]author\f[], \f[C]date\f[]
allow identification of basic aspects of the document.
Included in PDF metadata through LaTeX and ConTeXt.
@@ -1344,7 +1419,8 @@ body of document
.RE
.TP
.B \f[C]meta\-json\f[]
-JSON representation of all of the document's metadata
+JSON representation of all of the document's metadata.
+Field values are transformed to the selected output format.
.RS
.RE
.SS Language variables
@@ -1398,6 +1474,16 @@ engine is fully supported (use \f[C]\-\-latex\-engine=xelatex\f[]).
Variables are available for producing slide shows with pandoc, including
all reveal.js configuration options.
.TP
+.B \f[C]titlegraphic\f[]
+title graphic for Beamer documents
+.RS
+.RE
+.TP
+.B \f[C]logo\f[]
+logo for Beamer 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[])
@@ -1467,7 +1553,7 @@ LaTeX variables are used when creating a PDF.
.TP
.B \f[C]papersize\f[]
paper size, e.g.
-\f[C]letter\f[], \f[C]A4\f[]
+\f[C]letter\f[], \f[C]a4\f[]
.RS
.RE
.TP
@@ -1745,6 +1831,31 @@ adjusts text to left (\f[C]l\f[]), right (\f[C]r\f[]), center
if \f[C]true\f[] (the default), hyphenation will be used
.RS
.RE
+.SS Variables for ms
+.TP
+.B \f[C]pointsize\f[]
+point size (e.g.
+\f[C]10p\f[])
+.RS
+.RE
+.TP
+.B \f[C]lineheight\f[]
+line height (e.g.
+\f[C]12p\f[])
+.RS
+.RE
+.TP
+.B \f[C]fontfamily\f[]
+font family (e.g.
+\f[C]T\f[] or \f[C]P\f[])
+.RS
+.RE
+.TP
+.B \f[C]indent\f[]
+paragraph indent (e.g.
+\f[C]2m\f[])
+.RS
+.RE
.SS Using variables in templates
.PP
Variable names are sequences of alphanumerics, \f[C]\-\f[], and
@@ -1925,6 +2036,12 @@ I\ like\ several\ of\ their\ flavors\ of\ ice\ cream:
#22,\ for\ example,\ and\ #5.
\f[]
.fi
+.SS Extension: \f[C]space_in_atx_header\f[]
+.PP
+Many Markdown implementations do not require a space between the opening
+\f[C]#\f[]s of an ATX header and the header text, so that
+\f[C]#5\ bolt\f[] and \f[C]#hashtag\f[] count as headers.
+With this extension, pandoc does require the space.
.SS Header identifiers
.SS Extension: \f[C]header_attributes\f[]
.PP
@@ -2065,9 +2182,9 @@ 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.
+\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[]
@@ -2285,10 +2402,10 @@ 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.
+Currently, the only output formats that uses this information are HTML,
+LaTeX, Docx, and Ms.\ If highlighting is supported for your output
+format and language, then the code block above will appear highlighted,
+with numbered lines.
(To see which languages are supported, type
\f[C]pandoc\ \-\-list\-highlight\-languages\f[].) Otherwise, the code
block above will appear as follows:
@@ -3164,7 +3281,8 @@ 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:
+This form is necessary when the field contains blank lines or
+block\-level formatting:
.IP
.nf
\f[C]
@@ -3283,19 +3401,6 @@ This is a nice alternative to Markdown's \[lq]invisible\[rq] 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
-\[lq]Mr.\[rq]
-.PP
-Note: if your LaTeX template or any included header file call for the
-\f[C]csquotes\f[] package, pandoc will detect this automatically and use
-\f[C]\\enquote{...}\f[] for quoted text.
.SS Inline formatting
.SS Emphasis
.PP
@@ -3560,7 +3665,9 @@ 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 CodeCogs will be used
+For SVG images you can for example use
+\f[C]\-\-webtex\ https://latex.codecogs.com/svg.latex?\f[].
+If no URL is specified, the CodeCogs URL generating PNGs will be used
(\f[C]https://latex.codecogs.com/png.latex?\f[]).
.IP "7." 3
If the \f[C]\-\-mathjax\f[] option is used, TeX math will be displayed
@@ -3742,10 +3849,11 @@ 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.
+(There cannot be space between the two unless the
+\f[C]spaced_reference_links\f[] extension is enabled.) The link
+definition consists of the bracketed label, followed by a colon and a
+space, followed by the URL, and optionally (after a space) a link title
+either in quotes or in parentheses.
The label must not be parseable as a citation (assuming the
\f[C]citations\f[] extension is enabled): citations take precedence over
link labels.
@@ -3887,6 +3995,10 @@ One way to do this is to insert a nonbreaking space after the image:
![This\ image\ won\[aq]t\ be\ a\ figure](/url/of/image.png)\\\
\f[]
.fi
+.PP
+Note that in reveal.js slide shows, an image in a paragraph by itself
+that has the \f[C]stretch\f[] class will fill the screen, and the
+caption and figure tags will be omitted.
.SS Extension: \f[C]link_attributes\f[]
.PP
Attributes can be set on links and images:
@@ -4006,6 +4118,31 @@ note.]
.fi
.PP
Inline and regular footnotes may be mixed freely.
+.SS Typography
+.SS Extension: \f[C]smart\f[]
+.PP
+Interpret straight quotes as curly quotes, \f[C]\-\-\-\f[] as
+em\-dashes, \f[C]\-\-\f[] as en\-dashes, and \f[C]\&...\f[] as ellipses.
+Nonbreaking spaces are inserted after certain abbreviations, such as
+\[lq]Mr.\[rq] This option currently affects the input formats
+\f[C]markdown\f[], \f[C]commonmark\f[], \f[C]latex\f[],
+\f[C]mediawiki\f[], \f[C]org\f[], \f[C]rst\f[], and \f[C]twiki\f[], and
+the output formats \f[C]markdown\f[], \f[C]latex\f[], and
+\f[C]context\f[].
+.PP
+Note: If you are \f[I]writing\f[] Markdown, then the \f[C]smart\f[]
+extension has the reverse effect: what would have been curly quotes
+comes out straight.
+.PP
+In LaTeX, \f[C]smart\f[] means to use the standard TeX ligatures for
+quotation marks (\f[C]``\f[] and \f[C]\[aq]\[aq]\f[] for double quotes,
+\f[C]`\f[] and \f[C]\[aq]\f[] for single quotes) and dashes
+(\f[C]\-\-\f[] for en\-dash and \f[C]\-\-\-\f[] for em\-dash).
+If \f[C]smart\f[] is disabled, then in reading LaTeX pandoc will parse
+these characters literally.
+In writing LaTeX, enabling \f[C]smart\f[] tells pandoc to use the
+ligatures when possible; if \f[C]smart\f[] is disabled pandoc will use
+unicode quotation mark and dash characters.
.SS Citations
.SS Extension: \f[C]citations\f[]
.PP
@@ -4311,6 +4448,13 @@ 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]old_dashes\f[]
+.PP
+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 only has an effect if \f[C]smart\f[] is enabled.
+It is selected automatically for \f[C]textile\f[] input.
.SS Extension: \f[C]angle_brackets_escapable\f[]
.PP
Allow \f[C]<\f[] and \f[C]>\f[] to be backslash\-escaped, as they can be
@@ -4320,6 +4464,16 @@ This is implied by pandoc's default \f[C]all_symbols_escapable\f[].
.PP
Allow a list to occur right after a paragraph, with no intervening blank
space.
+.SS Extension: \f[C]spaced_reference_links\f[]
+.PP
+Allow whitespace between the two components of a reference link, for
+example,
+.IP
+.nf
+\f[C]
+[foo]\ [bar].
+\f[]
+.fi
.SS Extension: \f[C]hard_line_breaks\f[]
.PP
Causes all newlines within a paragraph to be interpreted as hard line
@@ -4593,6 +4747,9 @@ Headers \f[I]above\f[] the slide level in the hierarchy create
\[lq]title slides,\[rq] which just contain the section title and help to
break the slide show into sections.
.IP \[bu] 2
+Content \f[I]above\f[] the slide level will not appear in the slide
+show.
+.IP \[bu] 2
A title page is constructed automatically from the document's title
block, if present.
(In the case of beamer, this can be disabled by commenting out some
@@ -4887,7 +5044,7 @@ For example:
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
+output; \f[C]beamer\f[], \f[C]html4\f[] or \f[C]html5\f[] for output
only), pandoc will treat the document as literate Haskell source.
This means that
.IP \[bu] 2
@@ -4940,12 +5097,16 @@ pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
.PP
writes HTML with the Haskell code in bird tracks, so it can be copied
and pasted as literate Haskell source.
+.PP
+Note that GHC expects the bird tracks in the first column, so indentend
+literate code blocks (e.g.\ inside an itemized environment) will not be
+picked up by the Haskell compiler.
.SH SYNTAX HIGHLIGHTING
.PP
Pandoc will automatically highlight syntax in fenced code blocks that
are marked with a language name.
-The Haskell library highlighting\-kate is used for highlighting, which
-works in HTML, Docx, and LaTeX/PDF output.
+The Haskell library skylighting is used for highlighting, which works in
+HTML, Docx, Ms, and LaTeX/PDF output.
To see a list of language names that pandoc will recognize, type
\f[C]pandoc\ \-\-list\-highlight\-languages\f[].
.PP
@@ -5038,7 +5199,7 @@ pandoc\ \-\-print\-default\-data\-file\ sample.lua
.fi
.SH AUTHORS
.PP
-© 2006\-2016 John MacFarlane (jgm\@berkeley.edu).
+© 2006\-2017 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.)
diff --git a/pandoc.cabal b/pandoc.cabal
index f9ce1efd2..8d336097d 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -136,8 +136,15 @@ Extra-Source-Files:
test/*.native
test/command/*.md
test/command/abbrevs
+ test/command/SVG_logo-without-xml-declaration.svg
+ test/command/SVG_logo.svg
+ test/command/corrupt.svg
+ test/command/inkscape-cube.svg
test/command/sub-file-chapter-1.tex
test/command/sub-file-chapter-2.tex
+ test/command/3510-subdoc.org
+ test/command/3510-export.latex
+ test/command/3510-src.hs
test/docbook-reader.docbook
test/docbook-xref.docbook
test/html-reader.html
@@ -264,10 +271,6 @@ Flag weigh-pandoc
Description: Build weigh-pandoc to measure memory usage.
Default: False
-Flag https
- Description: Enable support for downloading of resources over https.
- Default: True
-
Flag network-uri
Description: Get Network.URI from the network-uri package
Default: True
@@ -316,7 +319,10 @@ Library
JuicyPixels >= 3.1.6.1 && < 3.3,
Glob >= 0.7 && < 0.8,
cmark >= 0.5 && < 0.6,
- doctemplates >= 0.1 && < 0.2
+ doctemplates >= 0.1 && < 0.2,
+ http-client >= 0.4.30 && < 0.6,
+ http-client-tls >= 0.2.4 && < 0.4,
+ http-types >= 0.8 && < 0.10
if os(windows)
Cpp-options: -D_WINDOWS
else
@@ -330,18 +336,10 @@ Library
Build-Depends: network-uri >= 2.6 && < 2.7, network >= 2.6
else
Build-Depends: network >= 2 && < 2.6
- if flag(https)
- Build-Depends: http-client >= 0.4.30 && < 0.6,
- http-client-tls >= 0.2.4 && < 0.4,
- http-types >= 0.8 && < 0.10
- cpp-options: -DHTTP_CLIENT
if flag(embed_data_files)
cpp-options: -DEMBED_DATA_FILES
build-depends: file-embed >= 0.0 && < 0.1
other-modules: Text.Pandoc.Data
- if os(darwin)
- Build-Tools: cpphs >= 1.19
- ghc-options: -pgmP cpphs -optP --cpp
if os(windows)
Cpp-options: -D_WINDOWS
Ghc-Options: -Wall -fno-warn-unused-do-bind
@@ -448,6 +446,7 @@ Library
Text.Pandoc.Readers.Odt.Arrows.Utils,
Text.Pandoc.Readers.Org.BlockStarts,
Text.Pandoc.Readers.Org.Blocks,
+ Text.Pandoc.Readers.Org.DocumentTree,
Text.Pandoc.Readers.Org.ExportSettings,
Text.Pandoc.Readers.Org.Inlines,
Text.Pandoc.Readers.Org.Meta,
@@ -508,6 +507,7 @@ Executable weigh-pandoc
if flag(weigh-pandoc)
Build-Depends: pandoc,
base >= 4.2 && < 5,
+ text,
weigh >= 0.0 && < 0.1,
mtl >= 2.2 && < 2.3
Buildable: True
@@ -585,7 +585,8 @@ benchmark benchmark-pandoc
Build-Depends: pandoc,
time, bytestring, containers,
base >= 4.2 && < 5,
+ text >= 0.11 && < 1.3,
syb >= 0.1 && < 0.8,
- criterion >= 1.0 && < 1.2
+ criterion >= 1.0 && < 1.3
Ghc-Options: -rtsopts -Wall -fno-warn-unused-do-bind
Default-Language: Haskell98
diff --git a/pandoc.hs b/pandoc.hs
index 6135aec03..7b749229c 100644
--- a/pandoc.hs
+++ b/pandoc.hs
@@ -1,5 +1,5 @@
{-# LANGUAGE CPP #-}
-{-# LANGUAGE PatternGuards #-}
+
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-
@@ -33,10 +33,11 @@ Parses command-line options and calls the appropriate readers and
writers.
-}
module Main where
-import Text.Pandoc.App (convertWithOpts, defaultOpts, options, parseOptions)
-import Text.Pandoc.Error (handleError, PandocError)
import qualified Control.Exception as E
+import Text.Pandoc.App (convertWithOpts, defaultOpts, options, parseOptions)
+import Text.Pandoc.Error (PandocError, handleError)
main :: IO ()
main = E.catch (parseOptions options defaultOpts >>= convertWithOpts)
(\(e :: PandocError) -> handleError (Left e))
+
diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs
index 345ef3b18..8ee1adf13 100644
--- a/src/Text/Pandoc.hs
+++ b/src/Text/Pandoc.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE GADTs #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/App.hs b/src/Text/Pandoc/App.hs
index c38ebdd84..19066e8b7 100644
--- a/src/Text/Pandoc/App.hs
+++ b/src/Text/Pandoc/App.hs
@@ -1,8 +1,9 @@
{-# LANGUAGE CPP #-}
+{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.App
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley@edu>
@@ -40,45 +41,50 @@ module Text.Pandoc.App (
import Control.Applicative ((<|>))
import qualified Control.Exception as E
import Control.Monad
+import Control.Monad.Except (throwError)
import Control.Monad.Trans
-import Data.Aeson (eitherDecode', encode)
+import Data.Monoid
+import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions, eitherDecode',
+ encode, genericToEncoding)
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as B
import Data.Char (toLower, toUpper)
-import qualified Data.Set as Set
import Data.Foldable (foldrM)
import Data.List (intercalate, isPrefixOf, isSuffixOf, sort)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust, isNothing)
+import qualified Data.Set as Set
+import Data.Text (Text)
import qualified Data.Text as T
import Data.Yaml (decode)
import qualified Data.Yaml as Yaml
-import Network.URI (URI (..), isURI, parseURI)
+import GHC.Generics
+import Network.URI (URI (..), parseURI)
import Paths_pandoc (getDataDir)
import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme)
-import Skylighting.Parser (missingIncludes, parseSyntaxDefinition,
- addSyntaxDefinition)
+import Skylighting.Parser (addSyntaxDefinition, missingIncludes,
+ parseSyntaxDefinition)
import System.Console.GetOpt
import System.Directory (Permissions (..), doesFileExist, findExecutable,
getAppUserDataDirectory, getPermissions)
import System.Environment (getArgs, getEnvironment, getProgName)
import System.Exit (ExitCode (..), exitSuccess)
import System.FilePath
-import System.IO (stdout)
+import System.IO (nativeNewline, stdout)
+import qualified System.IO as IO (Newline (..))
import System.IO.Error (isDoesNotExistError)
import Text.Pandoc
import Text.Pandoc.Builder (setMeta)
-import Text.Pandoc.Class (PandocIO, getLog, withMediaBag)
+import Text.Pandoc.Class (PandocIO, extractMedia, fillMediaBag, getLog,
+ setResourcePath, withMediaBag)
import Text.Pandoc.Highlighting (highlightingStyles)
-import Text.Pandoc.Lua ( runLuaFilter )
-import Text.Pandoc.MediaBag (MediaBag, extractMediaBag, mediaDirectory)
+import Text.Pandoc.Lua (runLuaFilter)
import Text.Pandoc.PDF (makePDF)
import Text.Pandoc.Process (pipeProcess)
-import Text.Pandoc.SelfContained (makeSelfContained, makeDataURI)
-import Text.Pandoc.Shared (headerShift, openURL, readDataFile,
+import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
+import Text.Pandoc.Shared (headerShift, isURI, openURL, readDataFile,
readDataFileUTF8, safeRead, tabFilter)
import qualified Text.Pandoc.UTF8 as UTF8
-import Text.Pandoc.Walk (walk)
import Text.Pandoc.XML (toEntities)
import Text.Printf
#ifndef _WINDOWS
@@ -86,6 +92,12 @@ import System.Posix.IO (stdOutput)
import System.Posix.Terminal (queryTerminal)
#endif
+data LineEnding = LF | CRLF | Native deriving (Show, Generic)
+
+instance ToJSON LineEnding where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON LineEnding
+
parseOptions :: [OptDescr (Opt -> IO Opt)] -> Opt -> IO Opt
parseOptions options' defaults = do
rawArgs <- map UTF8.decodeArg <$> getArgs
@@ -171,7 +183,7 @@ convertWithOpts opts = do
-- disabling the custom writer for now
writer <- if ".lua" `isSuffixOf` format
-- note: use non-lowercased version writerName
- then return (StringWriter
+ then return (TextWriter
(\o d -> liftIO $ writeCustom writerName o d)
:: Writer PandocIO)
else case getWriter writerName of
@@ -233,10 +245,9 @@ convertWithOpts opts = do
withList f (x:xs) vars = f x vars >>= withList f xs
variables <-
- return (("outputfile", optOutputFile opts) : optVariables opts)
- >>=
+
withList (addStringAsVariable "sourcefile")
- (reverse $ optInputFiles opts)
+ (reverse $ optInputFiles opts) (("outputfile", optOutputFile opts) : optVariables opts)
-- we reverse this list because, unlike
-- the other option lists here, it is
-- not reversed when parsed from CLI arguments.
@@ -372,8 +383,8 @@ convertWithOpts opts = do
then 0
else optTabStop opts)
- readSources :: (Functor m, MonadIO m) => [FilePath] -> m String
- readSources srcs = convertTabs . intercalate "\n" <$>
+ readSources :: [FilePath] -> PandocIO Text
+ readSources srcs = convertTabs . T.intercalate (T.pack "\n") <$>
mapM readSource srcs
let runIO' :: PandocIO a -> IO a
@@ -391,42 +402,47 @@ convertWithOpts opts = do
E.throwIO PandocFailOnWarningError
return res
- let sourceToDoc :: [FilePath] -> PandocIO (Pandoc, MediaBag)
+ let sourceToDoc :: [FilePath] -> PandocIO Pandoc
sourceToDoc sources' =
case reader of
- StringReader r
- | optFileScope opts || readerName == "json" -> do
- pairs <- mapM
- (readSource >=> withMediaBag . r readerOpts) sources
- return (mconcat (map fst pairs), mconcat (map snd pairs))
+ TextReader r
+ | optFileScope opts || readerName == "json" ->
+ mconcat <$> mapM (readSource >=> r readerOpts) sources
| otherwise ->
- readSources sources' >>= withMediaBag . r readerOpts
- ByteStringReader r -> do
- pairs <- mapM (readFile' >=>
- withMediaBag . r readerOpts) sources
- return (mconcat (map fst pairs), mconcat (map snd pairs))
+ readSources sources' >>= r readerOpts
+ ByteStringReader r ->
+ mconcat <$> mapM (readFile' >=> r readerOpts) sources
metadata <- if format == "jats" &&
- lookup "csl" (optMetadata opts) == Nothing &&
- lookup "citation-style" (optMetadata opts) == Nothing
+ isNothing (lookup "csl" (optMetadata opts)) &&
+ isNothing (lookup "citation-style" (optMetadata opts))
then do
jatsCSL <- readDataFile datadir "jats.csl"
let jatsEncoded = makeDataURI ("application/xml", jatsCSL)
return $ ("csl", jatsEncoded) : optMetadata opts
else return $ optMetadata opts
+ let eol = case optEol opts of
+ CRLF -> IO.CRLF
+ LF -> IO.LF
+ Native -> nativeNewline
+
runIO' $ do
- (doc, media) <- sourceToDoc sources
- doc' <- (maybe return (extractMedia media) (optExtractMedia opts) >=>
- return . flip (foldr addMetadata) metadata >=>
- applyTransforms transforms >=>
- applyLuaFilters datadir (optLuaFilters opts) [format] >=>
- applyFilters datadir filters' [format]) doc
+ setResourcePath (optResourcePath opts)
+ (doc, media) <- withMediaBag $ sourceToDoc sources >>=
+ ( (if isJust (optExtractMedia opts)
+ then fillMediaBag (writerSourceURL writerOptions)
+ else return)
+ >=> maybe return extractMedia (optExtractMedia opts)
+ >=> return . flip (foldr addMetadata) metadata
+ >=> applyTransforms transforms
+ >=> applyLuaFilters datadir (optLuaFilters opts) [format]
+ >=> applyFilters datadir filters' [format]
+ )
case writer of
- -- StringWriter f -> f writerOptions doc' >>= writerFn outputFile
- ByteStringWriter f -> f writerOptions doc' >>= writeFnBinary outputFile
- StringWriter f
+ ByteStringWriter f -> f writerOptions doc >>= writeFnBinary outputFile
+ TextWriter f
| pdfOutput -> do
-- make sure writer is latex, beamer, context, html5 or ms
unless (laTeXOutput || conTeXtOutput || html5Output ||
@@ -445,7 +461,7 @@ convertWithOpts opts = do
when (isNothing mbPdfProg) $ liftIO $ E.throwIO $
PandocPDFProgramNotFoundError pdfprog
- res <- makePDF pdfprog f writerOptions verbosity media doc'
+ res <- makePDF pdfprog f writerOptions verbosity media doc
case res of
Right pdf -> writeFnBinary outputFile pdf
Left err' -> liftIO $
@@ -453,18 +469,23 @@ convertWithOpts opts = do
| otherwise -> do
let htmlFormat = format `elem`
["html","html4","html5","s5","slidy","slideous","dzslides","revealjs"]
- selfcontain = if optSelfContained opts && htmlFormat
- then makeSelfContained writerOptions
- else return
handleEntities = if (htmlFormat ||
format == "docbook4" ||
format == "docbook5" ||
format == "docbook") && optAscii opts
then toEntities
else id
- output <- f writerOptions doc'
- selfcontain (output ++ ['\n' | not standalone]) >>=
- writerFn outputFile . handleEntities
+ addNl = if standalone
+ then id
+ else (<> T.singleton '\n')
+ output <- (addNl . handleEntities) <$> f writerOptions doc
+ writerFn eol outputFile =<<
+ if optSelfContained opts && htmlFormat
+ -- TODO not maximally efficient; change type
+ -- of makeSelfContained so it works w/ Text
+ then T.pack <$> makeSelfContained writerOptions
+ (T.unpack output)
+ else return output
type Transform = Pandoc -> Pandoc
@@ -568,7 +589,13 @@ data Opt = Opt
, optIncludeBeforeBody :: [FilePath] -- ^ Files to include before
, optIncludeAfterBody :: [FilePath] -- ^ Files to include after body
, optIncludeInHeader :: [FilePath] -- ^ Files to include in header
- }
+ , optResourcePath :: [FilePath] -- ^ Path to search for images etc
+ , optEol :: LineEnding -- ^ Style of line-endings to use
+ } deriving (Generic, Show)
+
+instance ToJSON Opt where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON Opt
-- | Defaults for command-line options.
defaultOpts :: Opt
@@ -636,6 +663,8 @@ defaultOpts = Opt
, optIncludeBeforeBody = []
, optIncludeAfterBody = []
, optIncludeInHeader = []
+ , optResourcePath = ["."]
+ , optEol = Native
}
addMetadata :: (String, String) -> Pandoc -> Pandoc
@@ -728,19 +757,6 @@ defaultWriterName x =
-- Transformations of a Pandoc document post-parsing:
-extractMedia :: MonadIO m => MediaBag -> FilePath -> Pandoc -> m Pandoc
-extractMedia media dir d =
- case [fp | (fp, _, _) <- mediaDirectory media] of
- [] -> return d
- fps -> do
- extractMediaBag True dir media
- return $ walk (adjustImagePath dir fps) d
-
-adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
-adjustImagePath dir paths (Image attr lab (src, tit))
- | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
-adjustImagePath _ _ x = x
-
applyTransforms :: Monad m => [Transform] -> Pandoc -> m Pandoc
applyTransforms transforms d = return $ foldr ($) d transforms
@@ -773,17 +789,23 @@ applyFilters mbDatadir filters args d = do
expandedFilters <- mapM (expandFilterPath mbDatadir) filters
foldrM ($) d $ map (flip externalFilter args) expandedFilters
-readSource :: MonadIO m => FilePath -> m String
-readSource "-" = liftIO UTF8.getContents
+readSource :: FilePath -> PandocIO Text
+readSource "-" = liftIO (UTF8.toText <$> BS.getContents)
readSource src = case parseURI src of
Just u | uriScheme u `elem` ["http:","https:"] ->
readURI src
| uriScheme u == "file:" ->
- liftIO $ UTF8.readFile (uriPath u)
- _ -> liftIO $ UTF8.readFile src
-
-readURI :: MonadIO m => FilePath -> m String
-readURI src = liftIO $ (UTF8.toString . fst) <$> openURL src
+ liftIO $ UTF8.toText <$>
+ BS.readFile (uriPath u)
+ _ -> liftIO $ UTF8.toText <$>
+ BS.readFile src
+
+readURI :: FilePath -> PandocIO Text
+readURI src = do
+ res <- liftIO $ openURL src
+ case res of
+ Left e -> throwError $ PandocHttpError src e
+ Right (contents, _) -> return $ UTF8.toText contents
readFile' :: MonadIO m => FilePath -> m B.ByteString
readFile' "-" = liftIO B.getContents
@@ -793,9 +815,10 @@ writeFnBinary :: MonadIO m => FilePath -> B.ByteString -> m ()
writeFnBinary "-" = liftIO . B.putStr
writeFnBinary f = liftIO . B.writeFile (UTF8.encodePath f)
-writerFn :: MonadIO m => FilePath -> String -> m ()
-writerFn "-" = liftIO . UTF8.putStr
-writerFn f = liftIO . UTF8.writeFile f
+writerFn :: MonadIO m => IO.Newline -> FilePath -> Text -> m ()
+-- TODO this implementation isn't maximally efficient:
+writerFn eol "-" = liftIO . UTF8.putStrWith eol . T.unpack
+writerFn eol f = liftIO . UTF8.writeFileWith eol f . T.unpack
lookupHighlightStyle :: Maybe String -> IO (Maybe Style)
lookupHighlightStyle Nothing = return Nothing
@@ -968,6 +991,19 @@ options =
"NUMBER")
"" -- "Dpi (default 96)"
+ , Option "" ["eol"]
+ (ReqArg
+ (\arg opt ->
+ case toLower <$> arg of
+ "crlf" -> return opt { optEol = CRLF }
+ "lf" -> return opt { optEol = LF }
+ "native" -> return opt { optEol = Native }
+ -- mac-syntax (cr) is not supported in ghc-base.
+ _ -> E.throwIO $ PandocOptionError
+ "--eol must be crlf, lf, or native")
+ "crlf|lf|native")
+ "" -- "EOL (default OS-dependent)"
+
, Option "" ["wrap"]
(ReqArg
(\arg opt ->
@@ -1046,6 +1082,14 @@ options =
"FILE")
"" -- "File to include after document body"
+ , Option "" ["resource-path"]
+ (ReqArg
+ (\arg opt -> return opt { optResourcePath =
+ splitSearchPath arg })
+ "SEARCHPATH")
+ "" -- "Paths to search for images and other resources"
+
+
, Option "" ["self-contained"]
(NoArg
(\opt -> return opt { optSelfContained = True,
@@ -1388,8 +1432,8 @@ options =
map ("--" ++) longs
let allopts = unwords (concatMap optnames options)
UTF8.hPutStrLn stdout $ printf tpl allopts
- (unwords readers'names)
- (unwords writers'names)
+ (unwords readersNames)
+ (unwords writersNames)
(unwords $ map fst highlightingStyles)
ddir
exitSuccess ))
@@ -1398,14 +1442,14 @@ options =
, Option "" ["list-input-formats"]
(NoArg
(\_ -> do
- mapM_ (UTF8.hPutStrLn stdout) readers'names
+ mapM_ (UTF8.hPutStrLn stdout) readersNames
exitSuccess ))
""
, Option "" ["list-output-formats"]
(NoArg
(\_ -> do
- mapM_ (UTF8.hPutStrLn stdout) writers'names
+ mapM_ (UTF8.hPutStrLn stdout) writersNames
exitSuccess ))
""
@@ -1509,14 +1553,15 @@ uppercaseFirstLetter :: String -> String
uppercaseFirstLetter (c:cs) = toUpper c : cs
uppercaseFirstLetter [] = []
-readers'names :: [String]
-readers'names = sort (map fst (readers :: [(String, Reader PandocIO)]))
+readersNames :: [String]
+readersNames = sort (map fst (readers :: [(String, Reader PandocIO)]))
-writers'names :: [String]
-writers'names = sort (map fst (writers :: [(String, Writer PandocIO)]))
+writersNames :: [String]
+writersNames = sort (map fst (writers :: [(String, Writer PandocIO)]))
splitField :: String -> (String, String)
splitField s =
case break (`elem` ":=") s of
(k,_:v) -> (k,v)
(k,[]) -> (k,"true")
+
diff --git a/src/Text/Pandoc/Asciify.hs b/src/Text/Pandoc/Asciify.hs
index 411a112b2..7125e5bcd 100644
--- a/src/Text/Pandoc/Asciify.hs
+++ b/src/Text/Pandoc/Asciify.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2013-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/CSS.hs b/src/Text/Pandoc/CSS.hs
index 3e2fd6309..41be1ea13 100644
--- a/src/Text/Pandoc/CSS.hs
+++ b/src/Text/Pandoc/CSS.hs
@@ -11,7 +11,7 @@ import Text.Parsec.String
ruleParser :: Parser (String, String)
ruleParser = do
p <- many1 (noneOf ":") <* char ':'
- v <- many1 (noneOf ":;") <* (optional $ char ';') <* spaces
+ v <- many1 (noneOf ":;") <* optional (char ';') <* spaces
return (trim p, trim v)
styleAttrParser :: Parser [(String, String)]
diff --git a/src/Text/Pandoc/Class.hs b/src/Text/Pandoc/Class.hs
index 1afa64c10..14a0b8044 100644
--- a/src/Text/Pandoc/Class.hs
+++ b/src/Text/Pandoc/Class.hs
@@ -1,6 +1,8 @@
-{-# LANGUAGE DeriveFunctor, DeriveDataTypeable, TypeSynonymInstances,
-FlexibleInstances, GeneralizedNewtypeDeriving, FlexibleContexts,
-StandaloneDeriving #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
+{-# LANGUAGE FlexibleContexts #-}
{-
Copyright (C) 2016 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -61,6 +63,8 @@ module Text.Pandoc.Class ( PandocMonad(..)
, runIOorExplode
, runPure
, withMediaBag
+ , fillMediaBag
+ , extractMedia
) where
import Prelude hiding (readFile)
@@ -76,8 +80,11 @@ import Text.Pandoc.Compat.Time (UTCTime)
import Text.Pandoc.Logging
import Text.Parsec (ParsecT)
import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
-import Text.Pandoc.MIME (MimeType, getMimeType)
+import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
+import Text.Pandoc.Definition
import Data.Char (toLower)
+import Data.Digest.Pure.SHA (sha1, showDigest)
+import Data.Maybe (fromMaybe)
import Data.Time.Clock.POSIX ( utcTimeToPOSIXSeconds
, posixSecondsToUTCTime
, POSIXTime )
@@ -86,13 +93,16 @@ import Network.URI ( escapeURIString, nonStrictRelativeTo,
unEscapeString, parseURIReference, isAllowedInURI,
parseURI, URI(..) )
import qualified Data.Time.LocalTime as IO (getCurrentTimeZone)
-import Text.Pandoc.MediaBag (MediaBag, lookupMedia)
+import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
+import Text.Pandoc.Walk (walkM, walk)
import qualified Text.Pandoc.MediaBag as MB
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified System.Environment as IO (lookupEnv)
import System.FilePath.Glob (match, compile)
-import System.FilePath ((</>), takeExtension, dropExtension, isRelative)
+import System.Directory (createDirectoryIfMissing)
+import System.FilePath ((</>), (<.>), takeDirectory,
+ takeExtension, dropExtension, isRelative, normalise)
import qualified System.FilePath.Glob as IO (glob)
import qualified System.Directory as IO (getModificationTime)
import Control.Monad as M (fail)
@@ -145,7 +155,7 @@ report :: PandocMonad m => LogMessage -> m ()
report msg = do
verbosity <- getsCommonState stVerbosity
let level = messageVerbosity msg
- when (level <= verbosity) $ do
+ when (level <= verbosity) $
logOutput msg
unless (level == DEBUG) $
modifyCommonState $ \st -> st{ stLog = msg : stLog st }
@@ -213,7 +223,7 @@ runIO :: PandocIO a -> IO (Either PandocError a)
runIO ma = flip evalStateT def $ runExceptT $ unPandocIO ma
withMediaBag :: PandocMonad m => m a -> m (a, MediaBag)
-withMediaBag ma = ((,)) <$> ma <*> getMediaBag
+withMediaBag ma = (,) <$> ma <*> getMediaBag
runIOorExplode :: PandocIO a -> IO a
runIOorExplode ma = runIO ma >>= handleError
@@ -239,10 +249,13 @@ instance PandocMonad PandocIO where
getCurrentTime = liftIO IO.getCurrentTime
getCurrentTimeZone = liftIO IO.getCurrentTimeZone
newStdGen = liftIO IO.newStdGen
- newUniqueHash = hashUnique <$> (liftIO IO.newUnique)
+ newUniqueHash = hashUnique <$> liftIO IO.newUnique
openURL u = do
report $ Fetching u
- liftIOError IO.openURL u
+ res <- liftIO (IO.openURL u)
+ case res of
+ Right r -> return r
+ Left e -> throwError $ PandocHttpError u e
readFileLazy s = liftIOError BL.readFile s
readFileStrict s = liftIOError B.readFile s
readDataFile mfp fname = liftIOError (IO.readDataFile mfp) fname
@@ -252,7 +265,7 @@ instance PandocMonad PandocIO where
putCommonState x = PandocIO $ lift $ put x
logOutput msg = liftIO $ do
UTF8.hPutStr stderr $ "[" ++
- (map toLower $ show (messageVerbosity msg)) ++ "] "
+ map toLower (show (messageVerbosity msg)) ++ "] "
alertIndent $ lines $ showLogMessage msg
alertIndent :: [String] -> IO ()
@@ -283,14 +296,14 @@ fetchItem :: PandocMonad m
fetchItem sourceURL s = do
mediabag <- getMediaBag
case lookupMedia s mediabag of
- Just (mime, bs) -> return $ (BL.toStrict bs, Just mime)
+ Just (mime, bs) -> return (BL.toStrict bs, Just mime)
Nothing -> downloadOrRead sourceURL s
downloadOrRead :: PandocMonad m
=> Maybe String
-> String
-> m (B.ByteString, Maybe MimeType)
-downloadOrRead sourceURL s = do
+downloadOrRead sourceURL s =
case (sourceURL >>= parseURIReference' .
ensureEscaped, ensureEscaped s) of
(Just u, s') -> -- try fetching from relative path at source
@@ -330,12 +343,73 @@ downloadOrRead sourceURL s = do
convertSlash x = x
withPaths :: PandocMonad m => [FilePath] -> (FilePath -> m a) -> FilePath -> m a
-withPaths [] _ fp = throwError $ PandocIOError fp
- (userError "file not found in resource path")
+withPaths [] _ fp = throwError $ PandocResourceNotFound fp
withPaths (p:ps) action fp =
catchError (action (p </> fp))
(\_ -> withPaths ps action fp)
+-- | Traverse tree, filling media bag for any images that
+-- aren't already in the media bag.
+fillMediaBag :: PandocMonad m => Maybe String -> Pandoc -> m Pandoc
+fillMediaBag sourceURL d = walkM handleImage d
+ where handleImage :: PandocMonad m => Inline -> m Inline
+ handleImage (Image attr lab (src, tit)) = catchError
+ (do mediabag <- getMediaBag
+ case lookupMedia src mediabag of
+ Just (_, _) -> return $ Image attr lab (src, tit)
+ Nothing -> do
+ (bs, mt) <- downloadOrRead sourceURL src
+ let ext = fromMaybe (takeExtension src)
+ (mt >>= extensionFromMimeType)
+ let bs' = BL.fromChunks [bs]
+ let basename = showDigest $ sha1 bs'
+ let fname = basename <.> ext
+ insertMedia fname mt bs'
+ return $ Image attr lab (fname, tit))
+ (\e ->
+ case e of
+ PandocResourceNotFound _ -> do
+ report $ CouldNotFetchResource src
+ "replacing image with description"
+ -- emit alt text
+ return $ Span ("",["image"],[]) lab
+ PandocHttpError u er -> do
+ report $ CouldNotFetchResource u
+ (show er ++ "\rReplacing image with description.")
+ -- emit alt text
+ return $ Span ("",["image"],[]) lab
+ _ -> throwError e)
+ handleImage x = return x
+
+-- | Extract media from the mediabag into a directory.
+extractMedia :: FilePath -> Pandoc -> PandocIO Pandoc
+extractMedia dir d = do
+ media <- getMediaBag
+ case [fp | (fp, _, _) <- mediaDirectory media] of
+ [] -> return d
+ fps -> do
+ mapM_ (writeMedia dir media) fps
+ return $ walk (adjustImagePath dir fps) d
+
+writeMedia :: FilePath -> MediaBag -> FilePath -> PandocIO ()
+writeMedia dir mediabag subpath = do
+ -- we join and split to convert a/b/c to a\b\c on Windows;
+ -- in zip containers all paths use /
+ let fullpath = dir </> normalise subpath
+ let mbcontents = lookupMedia subpath mediabag
+ case mbcontents of
+ Nothing -> throwError $ PandocResourceNotFound subpath
+ Just (_, bs) -> do
+ report $ Extracting fullpath
+ liftIO $ do
+ createDirectoryIfMissing True $ takeDirectory fullpath
+ BL.writeFile fullpath bs
+
+adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
+adjustImagePath dir paths (Image attr lab (src, tit))
+ | src `elem` paths = Image attr lab (dir ++ "/" ++ src, tit)
+adjustImagePath _ _ x = x
+
data PureState = PureState { stStdGen :: StdGen
, stWord8Store :: [Word8] -- should be
-- inifinite,
@@ -373,7 +447,7 @@ instance Default PureState where
getPureState :: PandocPure PureState
-getPureState = PandocPure $ lift $ lift $ get
+getPureState = PandocPure $ lift $ lift get
getsPureState :: (PureState -> a) -> PandocPure a
getsPureState f = f <$> getPureState
@@ -433,30 +507,27 @@ instance PandocMonad PandocPure where
modifyPureState $ \st -> st { stUniqStore = us }
return u
_ -> M.fail "uniq store ran out of elements"
- openURL u = throwError $ PandocIOError u $
- userError "Cannot open URL in PandocPure"
+ openURL u = throwError $ PandocResourceNotFound u
readFileLazy fp = do
fps <- getsPureState stFiles
case infoFileContents <$> getFileInfo fp fps of
Just bs -> return (BL.fromStrict bs)
- Nothing -> throwError $ PandocIOError fp
- (userError "File not found in PureState")
+ Nothing -> throwError $ PandocResourceNotFound fp
readFileStrict fp = do
fps <- getsPureState stFiles
case infoFileContents <$> getFileInfo fp fps of
Just bs -> return bs
- Nothing -> throwError $ PandocIOError fp
- (userError "File not found in PureState")
- readDataFile Nothing "reference.docx" = do
+ Nothing -> throwError $ PandocResourceNotFound fp
+ readDataFile Nothing "reference.docx" =
(B.concat . BL.toChunks . fromArchive) <$> getsPureState stReferenceDocx
- readDataFile Nothing "reference.odt" = do
+ readDataFile Nothing "reference.odt" =
(B.concat . BL.toChunks . fromArchive) <$> getsPureState stReferenceODT
readDataFile Nothing fname = do
let fname' = if fname == "MANUAL.txt" then fname else "data" </> fname
readFileStrict fname'
readDataFile (Just userDir) fname = do
userDirFiles <- getsPureState stUserDataDir
- case infoFileContents <$> (getFileInfo (userDir </> fname) userDirFiles) of
+ case infoFileContents <$> getFileInfo (userDir </> fname) userDirFiles of
Just bs -> return bs
Nothing -> readDataFile Nothing fname
@@ -466,12 +537,12 @@ instance PandocMonad PandocPure where
getModificationTime fp = do
fps <- getsPureState stFiles
- case infoFileMTime <$> (getFileInfo fp fps) of
+ case infoFileMTime <$> getFileInfo fp fps of
Just tm -> return tm
Nothing -> throwError $ PandocIOError fp
(userError "Can't get modification time")
- getCommonState = PandocPure $ lift $ get
+ getCommonState = PandocPure $ lift get
putCommonState x = PandocPure $ lift $ put x
logOutput _msg = return ()
@@ -555,4 +626,3 @@ instance PandocMonad m => PandocMonad (StateT st m) where
getCommonState = lift getCommonState
putCommonState = lift . putCommonState
logOutput = lift . logOutput
-
diff --git a/src/Text/Pandoc/Compat/Time.hs b/src/Text/Pandoc/Compat/Time.hs
index b1cde82a4..1de197801 100644
--- a/src/Text/Pandoc/Compat/Time.hs
+++ b/src/Text/Pandoc/Compat/Time.hs
@@ -27,4 +27,4 @@ where
import Data.Time
import System.Locale ( defaultTimeLocale )
-#endif
+#endif \ No newline at end of file
diff --git a/src/Text/Pandoc/Error.hs b/src/Text/Pandoc/Error.hs
index 135cb3945..3cf381168 100644
--- a/src/Text/Pandoc/Error.hs
+++ b/src/Text/Pandoc/Error.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Error
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -42,10 +42,12 @@ import Text.Parsec.Pos hiding (Line)
import qualified Text.Pandoc.UTF8 as UTF8
import System.Exit (exitWith, ExitCode(..))
import System.IO (stderr)
+import Network.HTTP.Client (HttpException)
type Input = String
data PandocError = PandocIOError String IOError
+ | PandocHttpError String HttpException
| PandocShouldNeverHappenError String
| PandocSomeError String
| PandocParseError String
@@ -58,6 +60,7 @@ data PandocError = PandocIOError String IOError
| PandocPDFError String
| PandocFilterError String String
| PandocCouldNotFindDataFileError String
+ | PandocResourceNotFound String
| PandocAppError String
deriving (Show, Typeable, Generic)
@@ -69,6 +72,8 @@ handleError (Right r) = return r
handleError (Left e) =
case e of
PandocIOError _ err' -> ioError err'
+ PandocHttpError u err' -> err 61 $
+ "Could not fetch " ++ u ++ "\n" ++ show err'
PandocShouldNeverHappenError s -> err 62 s
PandocSomeError s -> err 63 s
PandocParseError s -> err 64 s
@@ -78,7 +83,7 @@ handleError (Left e) =
errColumn = sourceColumn errPos
ls = lines input ++ [""]
errorInFile = if length ls > errLine - 1
- then concat ["\n", (ls !! (errLine - 1))
+ then concat ["\n", ls !! (errLine - 1)
,"\n", replicate (errColumn - 1) ' '
,"^"]
else ""
@@ -94,6 +99,8 @@ handleError (Left e) =
filtername ++ ":\n" ++ msg
PandocCouldNotFindDataFileError fn -> err 97 $
"Could not find data file " ++ fn
+ PandocResourceNotFound fn -> err 99 $
+ "File " ++ fn ++ " not found in resource path"
PandocAppError s -> err 1 s
err :: Int -> String -> IO a
diff --git a/src/Text/Pandoc/Extensions.hs b/src/Text/Pandoc/Extensions.hs
index 24f7d56ec..58e8c414d 100644
--- a/src/Text/Pandoc/Extensions.hs
+++ b/src/Text/Pandoc/Extensions.hs
@@ -137,6 +137,7 @@ data Extension =
| Ext_shortcut_reference_links -- ^ Shortcut reference links
| Ext_smart -- ^ "Smart" quotes, apostrophes, ellipses, dashes
| Ext_old_dashes -- ^ -- = em, - before number = en
+ | Ext_spaced_reference_links -- ^ Allow space between two parts of ref link
deriving (Show, Read, Enum, Eq, Ord, Bounded, Data, Typeable, Generic)
-- | Extensions to be used with pandoc-flavored markdown.
@@ -187,7 +188,7 @@ pandocExtensions = extensionsFromList
, Ext_smart
]
--- | Extensions to be used with github-flavored markdown.
+-- | Extensions to be used with plain text output.
plainExtensions :: Extensions
plainExtensions = extensionsFromList
[ Ext_table_captions
@@ -220,6 +221,7 @@ phpMarkdownExtraExtensions = extensionsFromList
, Ext_link_attributes
, Ext_abbreviations
, Ext_shortcut_reference_links
+ , Ext_spaced_reference_links
]
-- | Extensions to be used with github-flavored markdown.
@@ -271,6 +273,8 @@ multimarkdownExtensions = extensionsFromList
-- not to include these:
, Ext_superscript
, Ext_subscript
+ , Ext_backtick_code_blocks
+ , Ext_spaced_reference_links
]
-- | Language extensions to be used with strict markdown.
@@ -278,6 +282,7 @@ strictExtensions :: Extensions
strictExtensions = extensionsFromList
[ Ext_raw_html
, Ext_shortcut_reference_links
+ , Ext_spaced_reference_links
]
-- | Default extensions from format-describing string.
diff --git a/src/Text/Pandoc/Highlighting.hs b/src/Text/Pandoc/Highlighting.hs
index f249f96ad..0754aae4c 100644
--- a/src/Text/Pandoc/Highlighting.hs
+++ b/src/Text/Pandoc/Highlighting.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2008-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -91,7 +91,7 @@ highlight syntaxmap formatter (_, classes, keyvals) rawCode =
, traceOutput = False }
classes' = map T.pack classes
rawCode' = T.pack rawCode
- in case msum (map (\l -> lookupSyntax l syntaxmap) classes') of
+ in case msum (map ((`lookupSyntax` syntaxmap)) classes') of
Nothing
| numberLines fmtOpts -> Right
$ formatter fmtOpts{ codeClasses = [],
@@ -100,9 +100,9 @@ highlight syntaxmap formatter (_, classes, keyvals) rawCode =
$ T.lines rawCode'
| otherwise -> Left ""
Just syntax ->
- (formatter fmtOpts{ codeClasses =
+ formatter fmtOpts{ codeClasses =
[T.toLower (sShortname syntax)],
- containerClasses = classes' }) <$>
+ containerClasses = classes' } <$>
tokenize tokenizeOpts syntax rawCode'
-- Functions for correlating latex listings package's language names
diff --git a/src/Text/Pandoc/ImageSize.hs b/src/Text/Pandoc/ImageSize.hs
index 8b2d577a9..61ff006cf 100644
--- a/src/Text/Pandoc/ImageSize.hs
+++ b/src/Text/Pandoc/ImageSize.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
{-
- Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2011-2017 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 @@
{- |
Module : Text.Pandoc.ImageSize
-Copyright : Copyright (C) 2011-2016 John MacFarlane
+Copyright : Copyright (C) 2011-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -43,6 +43,7 @@ module Text.Pandoc.ImageSize ( ImageType(..)
, inInch
, inPixel
, inPoints
+ , inEm
, numUnit
, showInInch
, showInPixel
@@ -80,12 +81,14 @@ data Dimension = Pixel Integer
| Centimeter Double
| Inch Double
| Percent Double
+ | Em Double
instance Show Dimension where
show (Pixel a) = show a ++ "px"
show (Centimeter a) = showFl a ++ "cm"
show (Inch a) = showFl a ++ "in"
show (Percent a) = show a ++ "%"
+ show (Em a) = showFl a ++ "em"
data ImageSize = ImageSize{
pxX :: Integer
@@ -97,7 +100,13 @@ instance Default ImageSize where
def = ImageSize 300 200 72 72
showFl :: (RealFloat a) => a -> String
-showFl a = showFFloat (Just 5) a ""
+showFl a = removeExtra0s $ showFFloat (Just 5) a ""
+
+removeExtra0s :: String -> String
+removeExtra0s s =
+ case dropWhile (=='0') $ reverse s of
+ '.':xs -> reverse xs
+ xs -> reverse xs
imageType :: ByteString -> Maybe ImageType
imageType img = case B.take 4 img of
@@ -111,12 +120,12 @@ imageType img = case B.take 4 img of
| findSvgTag img
-> return Svg
"%!PS"
- | (B.take 4 $ B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
+ | B.take 4 (B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
-> return Eps
_ -> mzero
findSvgTag :: ByteString -> Bool
-findSvgTag img = B.null $ snd (B.breakSubstring img "<svg")
+findSvgTag img = "<svg" `B.isInfixOf` img || "<SVG" `B.isInfixOf` img
imageSize :: WriterOptions -> ByteString -> Either String ImageSize
imageSize opts img =
@@ -159,7 +168,7 @@ desiredSizeInPoints opts attr s =
(Nothing, Nothing) -> sizeInPoints s
where
ratio = fromIntegral (pxX s) / fromIntegral (pxY s)
- getDim dir = case (dimension dir attr) of
+ getDim dir = case dimension dir attr of
Just (Percent _) -> Nothing
Just dim -> Just $ inPoints opts dim
Nothing -> Nothing
@@ -167,13 +176,17 @@ desiredSizeInPoints opts attr s =
inPoints :: WriterOptions -> Dimension -> Double
inPoints opts dim = 72 * inInch opts dim
+inEm :: WriterOptions -> Dimension -> Double
+inEm opts dim = (64/11) * inInch opts dim
+
inInch :: WriterOptions -> Dimension -> Double
inInch opts dim =
case dim of
- (Pixel a) -> fromIntegral a / (fromIntegral $ writerDpi opts)
+ (Pixel a) -> fromIntegral a / fromIntegral (writerDpi opts)
(Centimeter a) -> a * 0.3937007874
(Inch a) -> a
(Percent _) -> 0
+ (Em a) -> a * (11/64)
inPixel :: WriterOptions -> Dimension -> Integer
inPixel opts dim =
@@ -181,7 +194,8 @@ inPixel opts dim =
(Pixel a) -> a
(Centimeter a) -> floor $ dpi * a * 0.3937007874 :: Integer
(Inch a) -> floor $ dpi * a :: Integer
- _ -> 0
+ (Percent _) -> 0
+ (Em a) -> floor $ dpi * a * (11/64) :: Integer
where
dpi = fromIntegral $ writerDpi opts
@@ -213,6 +227,7 @@ scaleDimension factor dim =
Centimeter x -> Centimeter (factor * x)
Inch x -> Inch (factor * x)
Percent x -> Percent (factor * x)
+ Em x -> Em (factor * x)
-- | Read a Dimension from an Attr attribute.
-- `dimension Width attr` might return `Just (Pixel 3)` or for example `Just (Centimeter 2.0)`, etc.
@@ -236,6 +251,7 @@ lengthToDim s = numUnit s >>= uncurry toDim
toDim a "" = Just $ Pixel (floor a::Integer)
toDim a "pt" = Just $ Inch (a / 72)
toDim a "pc" = Just $ Inch (a / 6)
+ toDim a "em" = Just $ Em a
toDim _ _ = Nothing
epsSize :: ByteString -> Maybe ImageSize
@@ -245,7 +261,7 @@ epsSize img = do
case ls' of
[] -> mzero
(x:_) -> case B.words x of
- (_:_:_:ux:uy:[]) -> do
+ [_, _, _, ux, uy] -> do
ux' <- safeRead $ B.unpack ux
uy' <- safeRead $ B.unpack uy
return ImageSize{
@@ -263,27 +279,26 @@ pngSize img = do
let (i, rest') = B.splitAt 4 $ B.drop 4 rest
guard $ i == "MHDR" || i == "IHDR"
let (sizes, rest'') = B.splitAt 8 rest'
- (x,y) <- case map fromIntegral $ unpack $ sizes of
+ (x,y) <- case map fromIntegral $unpack sizes of
([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)
+ (shift w1 24 + shift w2 16 + shift w3 8 + w4,
+ shift h1 24 + shift h2 16 + shift h3 8 + h4)
_ -> Nothing -- "PNG parse error"
let (dpix, dpiy) = findpHYs rest''
- return $ ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy }
+ return ImageSize { pxX = x, pxY = y, dpiX = dpix, dpiY = dpiy }
findpHYs :: ByteString -> (Integer, Integer)
-findpHYs x =
- if B.null x || "IDAT" `B.isPrefixOf` x
- then (72,72) -- default, no pHYs
- else if "pHYs" `B.isPrefixOf` x
- then let [x1,x2,x3,x4,y1,y2,y3,y4,u] = map fromIntegral
- $ unpack $ B.take 9 $ B.drop 4 x
- factor = if u == 1 -- dots per meter
- then \z -> z * 254 `div` 10000
- else const 72
- in ( factor $ (shift x1 24) + (shift x2 16) + (shift x3 8) + x4,
- factor $ (shift y1 24) + (shift y2 16) + (shift y3 8) + y4 )
- else findpHYs $ B.drop 1 x -- read another byte
+findpHYs x
+ | B.null x || "IDAT" `B.isPrefixOf` x = (72,72)
+ | "pHYs" `B.isPrefixOf` x =
+ let [x1,x2,x3,x4,y1,y2,y3,y4,u] =
+ map fromIntegral $ unpack $ B.take 9 $ B.drop 4 x
+ factor = if u == 1 -- dots per meter
+ then \z -> z * 254 `div` 10000
+ else const 72
+ in ( factor $ (shift x1 24) + (shift x2 16) + (shift x3 8) + x4,
+ factor $ (shift y1 24) + (shift y2 16) + (shift y3 8) + y4 )
+ | otherwise = findpHYs $ B.drop 1 x -- read another byte
gifSize :: ByteString -> Maybe ImageSize
gifSize img = do
@@ -327,16 +342,16 @@ jpegSize img =
jfifSize :: ByteString -> Either String ImageSize
jfifSize rest =
let [dpiDensity,dpix1,dpix2,dpiy1,dpiy2] = map fromIntegral
- $ unpack $ B.take 5 $ B.drop 9 $ rest
+ $ unpack $ B.take 5 $B.drop 9 rest
factor = case dpiDensity of
1 -> id
- 2 -> \x -> (x * 254 `div` 10)
+ 2 -> \x -> x * 254 `div` 10
_ -> const 72
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
+ Right (w,h) ->Right ImageSize { pxX = w
, pxY = h
, dpiX = dpix
, dpiY = dpiy }
@@ -370,7 +385,7 @@ runGet' p bl =
exifSize :: ByteString -> Either String ImageSize
-exifSize bs = runGet' header $ bl
+exifSize bs =runGet' header bl
where bl = BL.fromChunks [bs]
header = runExceptT $ exifHeader bl
-- NOTE: It would be nicer to do
@@ -440,14 +455,13 @@ exifHeader hdr = do
Left msg -> throwError msg
Right x -> return x
return (tag, payload)
- entries <- sequence $ replicate (fromIntegral numentries) ifdEntry
+ entries <- replicateM (fromIntegral numentries) ifdEntry
subentries <- case lookup ExifOffset entries of
Just (UnsignedLong offset') -> do
pos <- lift bytesRead
lift $ skip (fromIntegral offset' - (fromIntegral pos - 8))
numsubentries <- lift getWord16
- sequence $
- replicate (fromIntegral numsubentries) ifdEntry
+ replicateM (fromIntegral numsubentries) ifdEntry
_ -> return []
let allentries = entries ++ subentries
(wdth, hght) <- case (lookup ExifImageWidth allentries,
@@ -458,13 +472,13 @@ exifHeader hdr = do
-- we return a default width and height when
-- the exif header doesn't contain these
let resfactor = case lookup ResolutionUnit allentries of
- Just (UnsignedShort 1) -> (100 / 254)
+ Just (UnsignedShort 1) -> 100 / 254
_ -> 1
let xres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
$ lookup XResolution allentries
let yres = maybe 72 (\(UnsignedRational x) -> floor $ x * resfactor)
$ lookup YResolution allentries
- return $ ImageSize{
+ return ImageSize{
pxX = wdth
, pxY = hght
, dpiX = xres
@@ -588,3 +602,4 @@ tagTypeTable = M.fromList
, (0xa300, FileSource)
, (0xa301, SceneType)
]
+
diff --git a/src/Text/Pandoc/Logging.hs b/src/Text/Pandoc/Logging.hs
index 59b010034..da8c775f6 100644
--- a/src/Text/Pandoc/Logging.hs
+++ b/src/Text/Pandoc/Logging.hs
@@ -20,7 +20,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
Module : Text.Pandoc.Logging
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -39,6 +39,7 @@ module Text.Pandoc.Logging (
, messageVerbosity
) where
+import Control.Monad (mzero)
import Data.Aeson
import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
keyOrder)
@@ -56,12 +57,22 @@ data Verbosity = ERROR | WARNING | INFO | DEBUG
instance ToJSON Verbosity where
toJSON x = toJSON (show x)
+instance FromJSON Verbosity where
+ parseJSON (String t) =
+ case t of
+ "ERROR" -> return ERROR
+ "WARNING" -> return WARNING
+ "INFO" -> return INFO
+ "DEBUG" -> return DEBUG
+ _ -> mzero
+ parseJSON _ = mzero
data LogMessage =
SkippedContent String SourcePos
| CouldNotParseYamlMetadata String SourcePos
| DuplicateLinkReference String SourcePos
| DuplicateNoteReference String SourcePos
+ | NoteDefinedButNotUsed String SourcePos
| DuplicateIdentifier String SourcePos
| ReferenceNotFound String SourcePos
| CircularReference String SourcePos
@@ -78,6 +89,7 @@ data LogMessage =
| CouldNotConvertTeXMath String String
| CouldNotParseCSS String
| Fetching String
+ | Extracting String
| NoTitleElement String
| NoLangSpecified
| CouldNotHighlight String
@@ -103,6 +115,11 @@ instance ToJSON LogMessage where
"source" .= Text.pack (sourceName pos),
"line" .= toJSON (sourceLine pos),
"column" .= toJSON (sourceColumn pos)]
+ NoteDefinedButNotUsed s pos ->
+ ["key" .= Text.pack s,
+ "source" .= Text.pack (sourceName pos),
+ "line" .= toJSON (sourceLine pos),
+ "column" .= toJSON (sourceColumn pos)]
DuplicateNoteReference s pos ->
["contents" .= Text.pack s,
"source" .= Text.pack (sourceName pos),
@@ -162,6 +179,8 @@ instance ToJSON LogMessage where
["message" .= Text.pack msg]
Fetching fp ->
["path" .= Text.pack fp]
+ Extracting fp ->
+ ["path" .= Text.pack fp]
NoTitleElement fallback ->
["fallback" .= Text.pack fallback]
NoLangSpecified -> []
@@ -193,6 +212,9 @@ showLogMessage msg =
"Duplicate link reference '" ++ s ++ "' at " ++ showPos pos
DuplicateNoteReference s pos ->
"Duplicate note reference '" ++ s ++ "' at " ++ showPos pos
+ NoteDefinedButNotUsed s pos ->
+ "Note with key '" ++ s ++ "' defined at " ++ showPos pos ++
+ " but not used."
DuplicateIdentifier s pos ->
"Duplicate identifier '" ++ s ++ "' at " ++ showPos pos
ReferenceNotFound s pos ->
@@ -229,6 +251,8 @@ showLogMessage msg =
"Could not parse CSS" ++ if null m then "" else (':':'\n':m)
Fetching fp ->
"Fetching " ++ fp ++ "..."
+ Extracting fp ->
+ "Extracting " ++ fp ++ "..."
NoTitleElement fallback ->
"This document format requires a nonempty <title> element.\n" ++
"Please specify either 'title' or 'pagetitle' in the metadata.\n" ++
@@ -242,10 +266,11 @@ showLogMessage msg =
messageVerbosity:: LogMessage -> Verbosity
messageVerbosity msg =
case msg of
- SkippedContent{} -> INFO
+ SkippedContent{} -> WARNING
CouldNotParseYamlMetadata{} -> WARNING
DuplicateLinkReference{} -> WARNING
DuplicateNoteReference{} -> WARNING
+ NoteDefinedButNotUsed{} -> WARNING
DuplicateIdentifier{} -> WARNING
ReferenceNotFound{} -> WARNING
CircularReference{} -> WARNING
@@ -262,6 +287,7 @@ messageVerbosity msg =
CouldNotConvertTeXMath{} -> WARNING
CouldNotParseCSS{} -> WARNING
Fetching{} -> INFO
+ Extracting{} -> INFO
NoTitleElement{} -> WARNING
NoLangSpecified -> INFO
CouldNotHighlight{} -> WARNING
diff --git a/src/Text/Pandoc/Lua.hs b/src/Text/Pandoc/Lua.hs
index f4a22b92a..f74c0e425 100644
--- a/src/Text/Pandoc/Lua.hs
+++ b/src/Text/Pandoc/Lua.hs
@@ -15,8 +15,8 @@ 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
-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{- |
Module : Text.Pandoc.Lua
@@ -30,12 +30,12 @@ Pandoc lua utils.
-}
module Text.Pandoc.Lua ( runLuaFilter, pushPandocModule ) where
-import Control.Monad ( (>=>), when )
-import Control.Monad.Trans ( MonadIO(..) )
-import Data.Map ( Map )
-import Scripting.Lua ( LuaState, StackValue(..) )
+import Control.Monad (unless, when, (>=>))
+import Control.Monad.Trans (MonadIO (..))
+import Data.Map (Map)
+import Scripting.Lua (LuaState, StackValue (..))
import Text.Pandoc.Definition
-import Text.Pandoc.Lua.PandocModule ( pushPandocModule )
+import Text.Pandoc.Lua.PandocModule (pushPandocModule)
import Text.Pandoc.Lua.StackInstances ()
import Text.Pandoc.Walk
@@ -80,7 +80,7 @@ pushGlobalFilter lua =
*> Lua.rawseti lua (-2) 1
runAll :: [LuaFilter] -> Pandoc -> IO Pandoc
-runAll [] = return
+runAll [] = return
runAll (x:xs) = walkMWithLuaFilter x >=> runAll xs
walkMWithLuaFilter :: LuaFilter -> Pandoc -> IO Pandoc
@@ -225,7 +225,7 @@ instance StackValue LuaFilterFunction where
push lua v = pushFilterFunction lua v
peek lua i = do
isFn <- Lua.isfunction lua i
- when (not isFn) (error $ "Not a function at index " ++ (show i))
+ unless isFn (error $ "Not a function at index " ++ (show i))
Lua.pushvalue lua i
push lua ("PANDOC_FILTER_FUNCTIONS"::String)
Lua.rawget lua Lua.registryindex
diff --git a/src/Text/Pandoc/Lua/Compat.hs b/src/Text/Pandoc/Lua/Compat.hs
index 998d8d032..3fc81a15c 100644
--- a/src/Text/Pandoc/Lua/Compat.hs
+++ b/src/Text/Pandoc/Lua/Compat.hs
@@ -28,13 +28,13 @@ Compatibility helpers for hslua
-}
module Text.Pandoc.Lua.Compat ( loadstring ) where
-import Scripting.Lua ( LuaState )
+import Scripting.Lua (LuaState)
import qualified Scripting.Lua as Lua
-- | Interpret string as lua code and load into the lua environment.
loadstring :: LuaState -> String -> String -> IO Int
#if MIN_VERSION_hslua(0,5,0)
-loadstring lua script _ = Lua.loadstring lua script
+loadstring lua script _ = Lua.loadstring lua script
#else
loadstring lua script cn = Lua.loadstring lua script cn
#endif
diff --git a/src/Text/Pandoc/Lua/PandocModule.hs b/src/Text/Pandoc/Lua/PandocModule.hs
index 15f19f024..27c19d4f0 100644
--- a/src/Text/Pandoc/Lua/PandocModule.hs
+++ b/src/Text/Pandoc/Lua/PandocModule.hs
@@ -27,25 +27,24 @@ Pandoc module for lua.
-}
module Text.Pandoc.Lua.PandocModule ( pushPandocModule ) where
-import Data.ByteString.Char8 ( unpack )
-import Data.Default ( Default(..) )
-import Scripting.Lua ( LuaState, call, push, pushhsfunction, rawset)
-import Text.Pandoc.Class hiding ( readDataFile )
-import Text.Pandoc.Definition ( Pandoc )
-import Text.Pandoc.Lua.Compat ( loadstring )
+import Control.Monad (unless)
+import Data.ByteString.Char8 (unpack)
+import Data.Default (Default (..))
+import Data.Text (pack)
+import Scripting.Lua (LuaState, call, push, pushhsfunction, rawset)
+import Text.Pandoc.Class hiding (readDataFile)
+import Text.Pandoc.Definition (Pandoc)
+import Text.Pandoc.Lua.Compat (loadstring)
import Text.Pandoc.Lua.StackInstances ()
-import Text.Pandoc.Readers ( Reader(..), getReader )
-import Text.Pandoc.Shared ( readDataFile )
+import Text.Pandoc.Readers (Reader (..), getReader)
+import Text.Pandoc.Shared (readDataFile)
-- | Push the "pandoc" on the lua stack.
pushPandocModule :: LuaState -> IO ()
pushPandocModule lua = do
script <- pandocModuleScript
status <- loadstring lua script "pandoc.lua"
- if (status /= 0)
- then return ()
- else do
- call lua 0 1
+ unless (status /= 0) $ call lua 0 1
push lua "__read"
pushhsfunction lua read_doc
rawset lua (-3)
@@ -57,13 +56,13 @@ pandocModuleScript = unpack <$> readDataFile Nothing "pandoc.lua"
read_doc :: String -> String -> IO (Either String Pandoc)
read_doc formatSpec content = do
case getReader formatSpec of
- Left s -> return $ Left s
+ Left s -> return $ Left s
Right reader ->
case reader of
- StringReader r -> do
- res <- runIO $ r def content
+ TextReader r -> do
+ res <- runIO $ r def (pack content)
case res of
- Left s -> return . Left $ show s
+ Left s -> return . Left $ show s
Right pd -> return $ Right pd
_ -> return $ Left "Only string formats are supported at the moment."
diff --git a/src/Text/Pandoc/Lua/SharedInstances.hs b/src/Text/Pandoc/Lua/SharedInstances.hs
index 3d2d29ebf..a5d4ba1e9 100644
--- a/src/Text/Pandoc/Lua/SharedInstances.hs
+++ b/src/Text/Pandoc/Lua/SharedInstances.hs
@@ -1,5 +1,5 @@
{-
-Copyright © 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright © 2012-2017 John MacFarlane <jgm@berkeley.edu>
2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
@@ -16,9 +16,9 @@ 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
-}
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE LambdaCase #-}
#if !MIN_VERSION_base(4,8,0)
{-# LANGUAGE OverlappingInstances #-}
#endif
@@ -36,8 +36,8 @@ Shared StackValue instances for pandoc and generic types.
-}
module Text.Pandoc.Lua.SharedInstances () where
-import Scripting.Lua ( LTYPE(..), StackValue(..), newtable )
-import Text.Pandoc.Lua.Util ( addRawInt, addValue, getRawInt, keyValuePairs )
+import Scripting.Lua (LTYPE (..), StackValue (..), newtable)
+import Text.Pandoc.Lua.Util (addRawInt, addValue, getRawInt, keyValuePairs)
import qualified Data.Map as M
import qualified Text.Pandoc.UTF8 as UTF8
@@ -112,5 +112,5 @@ instance (StackValue a, StackValue b) => StackValue (Either a b) where
peek lua idx = peek lua idx >>= \case
Just left -> return . Just $ Left left
Nothing -> fmap Right <$> peek lua idx
- valuetype (Left x) = valuetype x
+ valuetype (Left x) = valuetype x
valuetype (Right x) = valuetype x
diff --git a/src/Text/Pandoc/Lua/StackInstances.hs b/src/Text/Pandoc/Lua/StackInstances.hs
index 03f6e06e2..d2e3f630a 100644
--- a/src/Text/Pandoc/Lua/StackInstances.hs
+++ b/src/Text/Pandoc/Lua/StackInstances.hs
@@ -1,5 +1,5 @@
{-
-Copyright © 2012-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright © 2012-2017 John MacFarlane <jgm@berkeley.edu>
2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
@@ -17,11 +17,11 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE LambdaCase #-}
+{-# LANGUAGE LambdaCase #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{- |
Module : Text.Pandoc.Lua.StackInstances
- Copyright : © 2012-2016 John MacFarlane
+ Copyright : © 2012-2017 John MacFarlane
© 2017 Albert Krewinkel
License : GNU GPL, version 2 or above
@@ -32,13 +32,13 @@ StackValue instances for pandoc types.
-}
module Text.Pandoc.Lua.StackInstances () where
-import Control.Applicative ( (<|>) )
-import Scripting.Lua
- ( LTYPE(..), LuaState, StackValue(..), ltype, newtable, objlen )
+import Control.Applicative ((<|>))
+import Scripting.Lua (LTYPE (..), LuaState, StackValue (..), ltype, newtable,
+ objlen)
import Text.Pandoc.Definition
import Text.Pandoc.Lua.SharedInstances ()
-import Text.Pandoc.Lua.Util ( addValue, getTable, pushViaConstructor )
-import Text.Pandoc.Shared ( safeRead )
+import Text.Pandoc.Lua.Util (addValue, getTable, pushViaConstructor)
+import Text.Pandoc.Shared (safeRead)
instance StackValue Pandoc where
push lua (Pandoc meta blocks) = do
diff --git a/src/Text/Pandoc/Lua/Util.hs b/src/Text/Pandoc/Lua/Util.hs
index f0b87c231..0a704d027 100644
--- a/src/Text/Pandoc/Lua/Util.hs
+++ b/src/Text/Pandoc/Lua/Util.hs
@@ -1,5 +1,5 @@
{-
-Copyright © 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright © 2012-2017 John MacFarlane <jgm@berkeley.edu>
2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
This program is free software; you can redistribute it and/or modify
@@ -42,10 +42,8 @@ module Text.Pandoc.Lua.Util
, pushViaConstructor
) where
-import Scripting.Lua
- ( LuaState, StackValue(..)
- , call, getglobal2, gettable, next, pop, pushnil, rawgeti, rawseti, settable
- )
+import Scripting.Lua (LuaState, StackValue (..), call, getglobal2, gettable,
+ next, pop, pushnil, rawgeti, rawseti, settable)
-- | Adjust the stack index, assuming that @n@ new elements have been pushed on
-- the stack.
diff --git a/src/Text/Pandoc/MIME.hs b/src/Text/Pandoc/MIME.hs
index 2e4a97b71..162112634 100644
--- a/src/Text/Pandoc/MIME.hs
+++ b/src/Text/Pandoc/MIME.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2011-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/MediaBag.hs b/src/Text/Pandoc/MediaBag.hs
index b865f97c2..d8d6da345 100644
--- a/src/Text/Pandoc/MediaBag.hs
+++ b/src/Text/Pandoc/MediaBag.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
-Copyright (C) 2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2014-2015, 2017 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.MediaBag
- Copyright : Copyright (C) 2014 John MacFarlane
+ Copyright : Copyright (C) 2014-2015, 2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,21 +35,15 @@ module Text.Pandoc.MediaBag (
lookupMedia,
insertMedia,
mediaDirectory,
- extractMediaBag
) where
-import Control.Monad (when)
-import Control.Monad.Trans (MonadIO (..))
import qualified Data.ByteString.Lazy as BL
import Data.Data (Data)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
import Data.Typeable (Typeable)
-import System.Directory (createDirectoryIfMissing)
import System.FilePath
import qualified System.FilePath.Posix as Posix
-import System.IO (stderr)
import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
-import qualified Text.Pandoc.UTF8 as UTF8
-- | A container for a collection of binary resources, with names and
-- mime types. Note that a 'MediaBag' is a Monoid, so 'mempty'
@@ -87,28 +81,3 @@ mediaDirectory :: MediaBag -> [(String, MimeType, Int)]
mediaDirectory (MediaBag mediamap) =
M.foldWithKey (\fp (mime,contents) ->
(((Posix.joinPath fp), mime, fromIntegral $ BL.length contents):)) [] mediamap
-
--- | Extract contents of MediaBag to a given directory. Print informational
--- messages if 'verbose' is true.
--- TODO: eventually we may want to put this into PandocMonad
--- In PandocPure, it could write to the fake file system...
-extractMediaBag :: MonadIO m
- => Bool
- -> FilePath
- -> MediaBag
- -> m ()
-extractMediaBag verbose dir (MediaBag mediamap) = liftIO $ do
- sequence_ $ M.foldWithKey
- (\fp (_ ,contents) ->
- ((writeMedia verbose dir (Posix.joinPath fp, contents)):)) [] mediamap
-
-writeMedia :: Bool -> FilePath -> (FilePath, BL.ByteString) -> IO ()
-writeMedia verbose dir (subpath, bs) = do
- -- we join and split to convert a/b/c to a\b\c on Windows;
- -- in zip containers all paths use /
- let fullpath = dir </> normalise subpath
- createDirectoryIfMissing True $ takeDirectory fullpath
- when verbose $ UTF8.hPutStrLn stderr $ "pandoc: extracting " ++ fullpath
- BL.writeFile fullpath bs
-
-
diff --git a/src/Text/Pandoc/Options.hs b/src/Text/Pandoc/Options.hs
index 0b09f0497..c7211c86e 100644
--- a/src/Text/Pandoc/Options.hs
+++ b/src/Text/Pandoc/Options.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2017 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.Options
- Copyright : Copyright (C) 2012-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -45,6 +45,8 @@ module Text.Pandoc.Options ( module Text.Pandoc.Extensions
, def
, isEnabled
) where
+import Data.Aeson (ToJSON(..), FromJSON(..),
+ genericToEncoding, defaultOptions)
import Data.Data (Data)
import Data.Default
import qualified Data.Set as Set
@@ -104,17 +106,29 @@ data HTMLMathMethod = PlainMath
| KaTeX String String -- url of stylesheet and katex.js
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON HTMLMathMethod where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON HTMLMathMethod
+
data CiteMethod = Citeproc -- use citeproc to render them
| Natbib -- output natbib cite commands
| Biblatex -- output biblatex cite commands
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON CiteMethod where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON CiteMethod
+
-- | Methods for obfuscating email addresses in HTML.
data ObfuscationMethod = NoObfuscation
| ReferenceObfuscation
| JavascriptObfuscation
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON ObfuscationMethod where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON ObfuscationMethod
+
-- | Varieties of HTML slide shows.
data HTMLSlideVariant = S5Slides
| SlidySlides
@@ -124,18 +138,30 @@ data HTMLSlideVariant = S5Slides
| NoSlides
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON HTMLSlideVariant where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON HTMLSlideVariant
+
-- | Options for accepting or rejecting MS Word track-changes.
data TrackChanges = AcceptChanges
| RejectChanges
| AllChanges
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON TrackChanges where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON TrackChanges
+
-- | Options for wrapping text in the output.
data WrapOption = WrapAuto -- ^ Automatically wrap to width
| WrapNone -- ^ No non-semantic newlines
| WrapPreserve -- ^ Preserve wrapping of input source
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON WrapOption where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON WrapOption
+
-- | Options defining the type of top-level headers.
data TopLevelDivision = TopLevelPart -- ^ Top-level headers become parts
| TopLevelChapter -- ^ Top-level headers become chapters
@@ -144,12 +170,20 @@ data TopLevelDivision = TopLevelPart -- ^ Top-level headers become parts
-- heuristics
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON TopLevelDivision where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON TopLevelDivision
+
-- | Locations for footnotes and references in markdown output
data ReferenceLocation = EndOfBlock -- ^ End of block
| EndOfSection -- ^ prior to next section header (or end of document)
| EndOfDocument -- ^ at end of document
deriving (Show, Read, Eq, Data, Typeable, Generic)
+instance ToJSON ReferenceLocation where
+ toEncoding = genericToEncoding defaultOptions
+instance FromJSON ReferenceLocation
+
-- | Options for writers
data WriterOptions = WriterOptions
{ writerTemplate :: Maybe String -- ^ Template to use
diff --git a/src/Text/Pandoc/PDF.hs b/src/Text/Pandoc/PDF.hs
index 696dbacf0..cd75d869d 100644
--- a/src/Text/Pandoc/PDF.hs
+++ b/src/Text/Pandoc/PDF.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2017 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.PDF
- Copyright : Copyright (C) 2012-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,15 +34,15 @@ module Text.Pandoc.PDF ( makePDF ) where
import qualified Codec.Picture as JP
import qualified Control.Exception as E
-import Control.Monad (unless, when, (<=<))
+import Control.Monad (unless, when)
import Control.Monad.Trans (MonadIO (..))
+import qualified Data.Text as T
+import Data.Text (Text)
import qualified Data.ByteString as BS
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.ByteString.Lazy.Char8 as BC
-import Data.Digest.Pure.SHA (sha1, showDigest)
-import Data.List (isInfixOf)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import System.Directory
@@ -53,7 +53,7 @@ import System.IO (stdout)
import System.IO.Temp (withTempDirectory, withTempFile)
import Text.Pandoc.Definition
import Text.Pandoc.MediaBag
-import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
+import Text.Pandoc.MIME (getMimeType)
import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
import Text.Pandoc.Process (pipeProcess)
import Text.Pandoc.Shared (inDirectory, stringify, withTempDir)
@@ -63,8 +63,9 @@ import Text.Pandoc.Writers.Shared (getField, metaToJSON)
#ifdef _WINDOWS
import Data.List (intercalate)
#endif
-import Text.Pandoc.Class (PandocIO, fetchItem, report, runIO, runIOorExplode,
- setMediaBag, setVerbosity)
+import Text.Pandoc.Class (PandocIO, report, runIO, runIOorExplode,
+ setMediaBag, setVerbosity, getResourcePath,
+ setResourcePath, fillMediaBag, extractMedia)
import Text.Pandoc.Logging
#ifdef _WINDOWS
@@ -72,16 +73,15 @@ changePathSeparators :: FilePath -> FilePath
changePathSeparators = intercalate "/" . splitDirectories
#endif
-makePDF :: MonadIO m
- => String -- ^ pdf creator (pdflatex, lualatex,
+makePDF :: String -- ^ pdf creator (pdflatex, lualatex,
-- xelatex, context, wkhtmltopdf, pdfroff)
- -> (WriterOptions -> Pandoc -> PandocIO String) -- ^ writer
+ -> (WriterOptions -> Pandoc -> PandocIO Text) -- ^ writer
-> WriterOptions -- ^ options
-> Verbosity -- ^ verbosity level
-> MediaBag -- ^ media
-> Pandoc -- ^ document
- -> m (Either ByteString ByteString)
-makePDF "wkhtmltopdf" writer opts verbosity _ doc@(Pandoc meta _) = liftIO $ do
+ -> PandocIO (Either ByteString ByteString)
+makePDF "wkhtmltopdf" writer opts verbosity _ doc@(Pandoc meta _) = do
let mathArgs = case writerHTMLMathMethod opts of
-- with MathJax, wait til all math is rendered:
MathJax _ -> ["--run-script", "MathJax.Hub.Register.StartupHook('End Typeset', function() { window.status = 'mathjax_loaded' });",
@@ -102,23 +102,20 @@ makePDF "wkhtmltopdf" writer opts verbosity _ doc@(Pandoc meta _) = liftIO $ do
,("margin-left", fromMaybe (Just "1.25in")
(getField "margin-left" meta'))
]
- source <- runIOorExplode $ do
- setVerbosity verbosity
- writer opts doc
- html2pdf verbosity args source
-makePDF "pdfroff" writer opts verbosity _mediabag doc = liftIO $ do
- source <- runIOorExplode $ do
- setVerbosity verbosity
- writer opts doc
+ source <- writer opts doc
+ liftIO $ html2pdf verbosity args source
+makePDF "pdfroff" writer opts verbosity _mediabag doc = do
+ source <- writer opts doc
let args = ["-ms", "-mpdfmark", "-e", "-t", "-k", "-KUTF-8", "-i",
"--no-toc-relocation"]
- ms2pdf verbosity args source
+ liftIO $ ms2pdf verbosity args source
makePDF program writer opts verbosity mediabag doc = do
let withTemp = if takeBaseName program == "context"
then withTempDirectory "."
else withTempDir
+ resourcePath <- getResourcePath
liftIO $ withTemp "tex2pdf." $ \tmpdir -> do
- doc' <- handleImages verbosity opts mediabag tmpdir doc
+ doc' <- handleImages verbosity opts resourcePath mediabag tmpdir doc
source <- runIOorExplode $ do
setVerbosity verbosity
writer opts doc'
@@ -131,44 +128,19 @@ makePDF program writer opts verbosity mediabag doc = do
handleImages :: Verbosity
-> WriterOptions
+ -> [FilePath]
-> MediaBag
-> FilePath -- ^ temp dir to store images
-> Pandoc -- ^ document
-> IO Pandoc
-handleImages verbosity opts mediabag tmpdir =
- walkM (convertImages verbosity tmpdir) <=<
- walkM (handleImage' verbosity opts mediabag tmpdir)
-
-handleImage' :: Verbosity
- -> WriterOptions
- -> MediaBag
- -> FilePath
- -> Inline
- -> IO Inline
-handleImage' verbosity opts mediabag tmpdir (Image attr ils (src,tit)) = do
- exists <- doesFileExist src
- if exists
- then return $ Image attr ils (src,tit)
- else do
- res <- runIO $ do
- setVerbosity verbosity
- setMediaBag mediabag
- fetchItem (writerSourceURL opts) src
- case res of
- Right (contents, Just mime) -> do
- let ext = fromMaybe (takeExtension src) $
- extensionFromMimeType mime
- let basename = showDigest $ sha1 $ BL.fromChunks [contents]
- let fname = tmpdir </> basename <.> ext
- BS.writeFile fname contents
- return $ Image attr ils (fname,tit)
- _ -> do
- runIO $ do
- setVerbosity verbosity
- report $ CouldNotFetchResource src "skipping..."
- -- return alt text
- return $ Emph ils
-handleImage' _ _ _ _ x = return x
+handleImages verbosity opts resourcePath mediabag tmpdir doc = do
+ doc' <- runIOorExplode $ do
+ setVerbosity verbosity
+ setResourcePath resourcePath
+ setMediaBag mediabag
+ fillMediaBag (writerSourceURL opts) doc >>=
+ extractMedia tmpdir
+ walkM (convertImages verbosity tmpdir) doc'
convertImages :: Verbosity -> FilePath -> Inline -> IO Inline
convertImages verbosity tmpdir (Image attr ils (src, tit)) = do
@@ -191,6 +163,7 @@ convertImage tmpdir fname =
Just "image/png" -> doNothing
Just "image/jpeg" -> doNothing
Just "application/pdf" -> doNothing
+ Just "image/svg+xml" -> return $ Left "conversion from svg not supported"
_ -> JP.readImage fname >>= \res ->
case res of
Left e -> return $ Left e
@@ -206,10 +179,10 @@ tex2pdf' :: Verbosity -- ^ Verbosity level
-> [String] -- ^ Arguments to the latex-engine
-> FilePath -- ^ temp directory for output
-> String -- ^ tex program
- -> String -- ^ tex source
+ -> Text -- ^ tex source
-> IO (Either ByteString ByteString)
tex2pdf' verbosity args tmpDir program source = do
- let numruns = if "\\tableofcontents" `isInfixOf` source
+ let numruns = if "\\tableofcontents" `T.isInfixOf` source
then 3 -- to get page numbers
else 2 -- 1 run won't give you PDF bookmarks
(exit, log', mbPdf) <- runTeXProgram verbosity program args 1 numruns tmpDir source
@@ -251,11 +224,11 @@ extractConTeXtMsg log' = do
-- contents of stdout, contents of produced PDF if any). Rerun
-- a fixed number of times to resolve references.
runTeXProgram :: Verbosity -> String -> [String] -> Int -> Int -> FilePath
- -> String -> IO (ExitCode, ByteString, Maybe ByteString)
+ -> Text -> IO (ExitCode, ByteString, Maybe ByteString)
runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
let file = tmpDir </> "input.tex"
exists <- doesFileExist file
- unless exists $ UTF8.writeFile file source
+ unless exists $ BS.writeFile file $ UTF8.fromText source
#ifdef _WINDOWS
-- note: we want / even on Windows, for TexLive
let tmpDir' = changePathSeparators tmpDir
@@ -304,7 +277,7 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
ms2pdf :: Verbosity
-> [String]
- -> String
+ -> Text
-> IO (Either ByteString ByteString)
ms2pdf verbosity args source = do
env' <- getEnvironment
@@ -316,10 +289,10 @@ ms2pdf verbosity args source = do
mapM_ print env'
putStr "\n"
putStrLn $ "[makePDF] Contents:\n"
- putStr source
+ putStr $ T.unpack source
putStr "\n"
(exit, out) <- pipeProcess (Just env') "pdfroff" args
- (UTF8.fromStringLazy source)
+ (BL.fromStrict $ UTF8.fromText source)
when (verbosity >= INFO) $ do
B.hPutStr stdout out
putStr "\n"
@@ -329,12 +302,12 @@ ms2pdf verbosity args source = do
html2pdf :: Verbosity -- ^ Verbosity level
-> [String] -- ^ Args to wkhtmltopdf
- -> String -- ^ HTML5 source
+ -> Text -- ^ HTML5 source
-> IO (Either ByteString ByteString)
html2pdf verbosity args source = do
file <- withTempFile "." "html2pdf.html" $ \fp _ -> return fp
pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp
- UTF8.writeFile file source
+ BS.writeFile file $ UTF8.fromText source
let programArgs = args ++ [file, pdfFile]
env' <- getEnvironment
when (verbosity >= INFO) $ do
@@ -369,11 +342,11 @@ html2pdf verbosity args source = do
context2pdf :: Verbosity -- ^ Verbosity level
-> FilePath -- ^ temp directory for output
- -> String -- ^ ConTeXt source
+ -> Text -- ^ ConTeXt source
-> IO (Either ByteString ByteString)
context2pdf verbosity tmpDir source = inDirectory tmpDir $ do
let file = "input.tex"
- UTF8.writeFile file source
+ BS.writeFile file $ UTF8.fromText source
#ifdef _WINDOWS
-- note: we want / even on Windows, for TexLive
let tmpDir' = changePathSeparators tmpDir
diff --git a/src/Text/Pandoc/Parsing.hs b/src/Text/Pandoc/Parsing.hs
index a6d3cd46a..cd51bff69 100644
--- a/src/Text/Pandoc/Parsing.hs
+++ b/src/Text/Pandoc/Parsing.hs
@@ -7,7 +7,7 @@
, IncoherentInstances #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
@@ -26,7 +26,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Parsing
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -36,6 +36,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
A utility library with parsers used in pandoc readers.
-}
module Text.Pandoc.Parsing ( anyLine,
+ anyLineNewline,
+ indentWith,
many1Till,
notFollowedBy',
oneOfStrings,
@@ -48,6 +50,7 @@ module Text.Pandoc.Parsing ( anyLine,
enclosed,
stringAnyCase,
parseFromString,
+ parseFromString',
lineClump,
charsInBalanced,
romanNumeral,
@@ -66,6 +69,7 @@ module Text.Pandoc.Parsing ( anyLine,
tableWith,
widthsFromIndices,
gridTableWith,
+ gridTableWith',
readWith,
readWithM,
testStringWith,
@@ -82,6 +86,7 @@ module Text.Pandoc.Parsing ( anyLine,
HasMacros (..),
HasLogMessages (..),
HasLastStrPosition (..),
+ HasIncludeFiles (..),
defaultParserState,
HeaderType (..),
ParserContext (..),
@@ -119,6 +124,7 @@ module Text.Pandoc.Parsing ( anyLine,
(<+?>),
extractIdClass,
insertIncludedFile,
+ insertIncludedFileF,
-- * Re-exports from Text.Pandoc.Parsec
Stream,
runParser,
@@ -252,12 +258,28 @@ anyLine = do
return this
_ -> mzero
+-- | Parse any line, include the final newline in the output
+anyLineNewline :: Stream [Char] m Char => ParserT [Char] st m [Char]
+anyLineNewline = (++ "\n") <$> anyLine
+
+-- | Parse indent by specified number of spaces (or equiv. tabs)
+indentWith :: Stream [Char] m Char
+ => HasReaderOptions st
+ => Int -> ParserT [Char] st m [Char]
+indentWith num = do
+ tabStop <- getOption readerTabStop
+ if (num < tabStop)
+ then count num (char ' ')
+ else choice [ try (count num (char ' '))
+ , try (char '\t' >> indentWith (num - tabStop)) ]
+
-- | Like @manyTill@, but reads at least one item.
-many1Till :: Stream s m t
+many1Till :: (Show end, Stream s m t)
=> ParserT s st m a
-> ParserT s st m end
-> ParserT s st m [a]
many1Till p end = do
+ notFollowedBy' end
first <- p
rest <- manyTill p end
return (first:rest)
@@ -322,7 +344,7 @@ blanklines :: Stream s m Char => ParserT s st m [Char]
blanklines = many1 blankline
-- | Parses material enclosed between start and end parsers.
-enclosed :: Stream s m Char => ParserT s st m t -- ^ start parser
+enclosed :: (Show end, Stream s m Char) => ParserT s st m t -- ^ start parser
-> ParserT s st m end -- ^ end parser
-> ParserT s st m a -- ^ content parser (to be used repeatedly)
-> ParserT s st m [a]
@@ -338,7 +360,10 @@ stringAnyCase (x:xs) = do
return (firstChar:rest)
-- | Parse contents of 'str' using 'parser' and return result.
-parseFromString :: Monad m => ParserT String st m a -> String -> ParserT String 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
@@ -350,6 +375,18 @@ parseFromString parser str = do
setPosition oldPos
return result
+-- | Like 'parseFromString' but specialized for 'ParserState'.
+-- This resets 'stateLastStrPos', which is almost always what we want.
+parseFromString' :: Monad m
+ => ParserT String ParserState m a
+ -> String
+ -> ParserT String ParserState m a
+parseFromString' parser str = do
+ oldStrPos <- stateLastStrPos <$> getState
+ res <- parseFromString parser str
+ updateState $ \st -> st{ stateLastStrPos = oldStrPos }
+ return res
+
-- | Parse raw line block up to and including blank lines.
lineClump :: Stream [Char] m Char => ParserT [Char] st m String
lineClump = blanklines
@@ -445,33 +482,8 @@ emailAddress = try $ toResult <$> mailbox <*> (char '@' *> domain)
sepby1 p sep = (:) <$> p <*> (many (try $ sep >> p))
--- Schemes from http://www.iana.org/assignments/uri-schemes.html plus
--- the unofficial schemes coap, doi, javascript, isbn, pmid
-schemes :: [String]
-schemes = ["coap","doi","javascript","aaa","aaas","about","acap","cap","cid",
- "crid","data","dav","dict","dns","file","ftp","geo","go","gopher",
- "h323","http","https","iax","icap","im","imap","info","ipp","iris",
- "iris.beep","iris.xpc","iris.xpcs","iris.lwz","ldap","mailto","mid",
- "msrp","msrps","mtqp","mupdate","news","nfs","ni","nih","nntp",
- "opaquelocktoken","pop","pres","rtsp","service","session","shttp","sieve",
- "sip","sips","sms","snmp","soap.beep","soap.beeps","tag","tel","telnet",
- "tftp","thismessage","tn3270","tip","tv","urn","vemmi","ws","wss","xcon",
- "xcon-userid","xmlrpc.beep","xmlrpc.beeps","xmpp","z39.50r","z39.50s",
- "adiumxtra","afp","afs","aim","apt","attachment","aw","beshare","bitcoin",
- "bolo","callto","chrome","chrome-extension","com-eventbrite-attendee",
- "content", "cvs","dlna-playsingle","dlna-playcontainer","dtn","dvb",
- "ed2k","facetime","feed","finger","fish","gg","git","gizmoproject",
- "gtalk","hcp","icon","ipn","irc","irc6","ircs","itms","jar","jms",
- "keyparc","lastfm","ldaps","magnet","maps","market","message","mms",
- "ms-help","msnim","mumble","mvn","notes","oid","palm","paparazzi",
- "platform","proxy","psyc","query","res","resource","rmi","rsync",
- "rtmp","secondlife","sftp","sgn","skype","smb","soldat","spotify",
- "ssh","steam","svn","teamspeak","things","udp","unreal","ut2004",
- "ventrilo","view-source","webcal","wtai","wyciwyg","xfire","xri",
- "ymsgr", "isbn", "pmid"]
-
uriScheme :: Stream s m Char => ParserT s st m String
-uriScheme = oneOfStringsCI schemes
+uriScheme = oneOfStringsCI (Set.toList schemes)
-- | Parses a URI. Returns pair of original and URI-escaped version.
uri :: Stream [Char] m Char => ParserT [Char] st m (String, String)
@@ -762,21 +774,36 @@ lineBlockLines = try $ do
-- | Parse a table using 'headerParser', 'rowParser',
-- 'lineParser', and 'footerParser'.
-tableWith :: Stream s m Char
- => ParserT s ParserState m ([Blocks], [Alignment], [Int])
- -> ([Int] -> ParserT s ParserState m [Blocks])
- -> ParserT s ParserState m sep
- -> ParserT s ParserState m end
- -> ParserT s ParserState m Blocks
+tableWith :: (Stream s m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT s st m (mf [Blocks], [Alignment], [Int])
+ -> ([Int] -> ParserT s st m (mf [Blocks]))
+ -> ParserT s st m sep
+ -> ParserT s st m end
+ -> ParserT s st m (mf Blocks)
tableWith headerParser rowParser lineParser footerParser = try $ do
+ (aligns, widths, heads, rows) <- tableWith' headerParser rowParser
+ lineParser footerParser
+ return $ B.table mempty (zip aligns widths) <$> heads <*> rows
+
+type TableComponents mf = ([Alignment], [Double], mf [Blocks], mf [[Blocks]])
+
+tableWith' :: (Stream s m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT s st m (mf [Blocks], [Alignment], [Int])
+ -> ([Int] -> ParserT s st m (mf [Blocks]))
+ -> ParserT s st m sep
+ -> ParserT s st m end
+ -> ParserT s st m (TableComponents mf)
+tableWith' headerParser rowParser lineParser footerParser = try $ do
(heads, aligns, indices) <- headerParser
- lines' <- rowParser indices `sepEndBy1` lineParser
+ lines' <- sequence <$> rowParser indices `sepEndBy1` lineParser
footerParser
numColumns <- getOption readerColumns
let widths = if (indices == [])
then replicate (length aligns) 0.0
else widthsFromIndices numColumns indices
- return $ B.table mempty (zip aligns widths) heads lines'
+ return $ (aligns, widths, heads, lines')
-- Calculate relative widths of table columns, based on indices
widthsFromIndices :: Int -- Number of columns on terminal
@@ -809,25 +836,44 @@ widthsFromIndices numColumns' indices =
-- (which may be grid), then the rows,
-- which may be grid, separated by blank lines, and
-- ending with a footer (dashed line followed by blank line).
-gridTableWith :: Stream [Char] m Char
- => ParserT [Char] ParserState m Blocks -- ^ Block list parser
- -> Bool -- ^ Headerless table
- -> ParserT [Char] ParserState m Blocks
+gridTableWith :: (Stream [Char] m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks) -- ^ Block list parser
+ -> Bool -- ^ Headerless table
+ -> ParserT [Char] st m (mf Blocks)
gridTableWith blocks headless =
tableWith (gridTableHeader headless blocks) (gridTableRow blocks)
(gridTableSep '-') gridTableFooter
+gridTableWith' :: (Stream [Char] m Char, HasReaderOptions st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks) -- ^ Block list parser
+ -> Bool -- ^ Headerless table
+ -> ParserT [Char] st m (TableComponents mf)
+gridTableWith' blocks headless =
+ tableWith' (gridTableHeader headless blocks) (gridTableRow blocks)
+ (gridTableSep '-') gridTableFooter
+
gridTableSplitLine :: [Int] -> String -> [String]
gridTableSplitLine indices line = map removeFinalBar $ tail $
splitStringByIndices (init indices) $ trimr line
-gridPart :: Stream s m Char => Char -> ParserT s st m (Int, Int)
+gridPart :: Stream s m Char => Char -> ParserT s st m ((Int, Int), Alignment)
gridPart ch = do
+ leftColon <- option False (True <$ char ':')
dashes <- many1 (char ch)
+ rightColon <- option False (True <$ char ':')
char '+'
- return (length dashes, length dashes + 1)
-
-gridDashedLines :: Stream s m Char => Char -> ParserT s st m [(Int,Int)]
+ let lengthDashes = length dashes + (if leftColon then 1 else 0) +
+ (if rightColon then 1 else 0)
+ let alignment = case (leftColon, rightColon) of
+ (True, True) -> AlignCenter
+ (True, False) -> AlignLeft
+ (False, True) -> AlignRight
+ (False, False) -> AlignDefault
+ return ((lengthDashes, lengthDashes + 1), alignment)
+
+gridDashedLines :: Stream s m Char => Char -> ParserT s st m [((Int, Int), Alignment)]
gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
removeFinalBar :: String -> String
@@ -835,14 +881,14 @@ removeFinalBar =
reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
-- | Separator between rows of grid table.
-gridTableSep :: Stream s m Char => Char -> ParserT s ParserState m Char
+gridTableSep :: Stream s m Char => Char -> ParserT s st m Char
gridTableSep ch = try $ gridDashedLines ch >> return '\n'
-- | Parse header for a grid table.
-gridTableHeader :: Stream [Char] m Char
+gridTableHeader :: (Stream [Char] m Char, Functor mf, Applicative mf, Monad mf)
=> Bool -- ^ Headerless table
- -> ParserT [Char] ParserState m Blocks
- -> ParserT [Char] ParserState m ([Blocks], [Alignment], [Int])
+ -> ParserT [Char] st m (mf Blocks)
+ -> ParserT [Char] st m (mf [Blocks], [Alignment], [Int])
gridTableHeader headless blocks = try $ do
optional blanklines
dashes <- gridDashedLines '-'
@@ -851,36 +897,40 @@ gridTableHeader headless blocks = try $ do
else many1
(notFollowedBy (gridTableSep '=') >> char '|' >>
many1Till anyChar newline)
- if headless
- then return ()
- else gridTableSep '=' >> return ()
- let lines' = map snd dashes
+ underDashes <- if headless
+ then return dashes
+ else gridDashedLines '='
+ guard $ length dashes == length underDashes
+ let lines' = map (snd . fst) underDashes
let indices = scanl (+) 0 lines'
- let aligns = replicate (length lines') AlignDefault
- -- RST does not have a notion of alignments
+ let aligns = map snd underDashes
let rawHeads = if headless
- then replicate (length dashes) ""
- else map (intercalate " ") $ transpose
+ then replicate (length underDashes) ""
+ else map (unlines . map trim) $ transpose
$ map (gridTableSplitLine indices) rawContent
- heads <- mapM (parseFromString blocks) $ map trim rawHeads
+ heads <- fmap sequence $ mapM (parseFromString blocks . trim) rawHeads
return (heads, aligns, indices)
-gridTableRawLine :: Stream s m Char => [Int] -> ParserT s ParserState m [String]
+gridTableRawLine :: Stream s m Char => [Int] -> ParserT s st m [String]
gridTableRawLine indices = do
char '|'
line <- many1Till anyChar newline
return (gridTableSplitLine indices line)
-- | Parse row of grid table.
-gridTableRow :: Stream [Char] m Char
- => ParserT [Char] ParserState m Blocks
+gridTableRow :: (Stream [Char] m Char, Functor mf, Applicative mf, Monad mf)
+ => ParserT [Char] st m (mf Blocks)
-> [Int]
- -> ParserT [Char] ParserState m [Blocks]
+ -> ParserT [Char] st m (mf [Blocks])
gridTableRow blocks indices = do
colLines <- many1 (gridTableRawLine indices)
let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
transpose colLines
- mapM (liftM compactifyCell . parseFromString blocks) cols
+ compactifyCell bs = case compactify [bs] of
+ [] -> mempty
+ x:_ -> x
+ cells <- sequence <$> mapM (parseFromString blocks) cols
+ return $ fmap (map compactifyCell) cells
removeOneLeadingSpace :: [String] -> [String]
removeOneLeadingSpace xs =
@@ -890,11 +940,8 @@ removeOneLeadingSpace xs =
where startsWithSpace "" = True
startsWithSpace (y:_) = y == ' '
-compactifyCell :: Blocks -> Blocks
-compactifyCell bs = head $ compactify [bs]
-
-- | Parse footer for a grid table.
-gridTableFooter :: Stream s m Char => ParserT s ParserState m [Char]
+gridTableFooter :: Stream s m Char => ParserT s st m [Char]
gridTableFooter = blanklines
---
@@ -937,6 +984,7 @@ data ParserState = ParserState
stateSubstitutions :: SubstTable, -- ^ List of substitution references
stateNotes :: NoteTable, -- ^ List of notes (raw bodies)
stateNotes' :: NoteTable', -- ^ List of notes (parsed bodies)
+ stateNoteRefs :: Set.Set String, -- ^ List of note references used
stateMeta :: Meta, -- ^ Document metadata
stateMeta' :: F Meta, -- ^ Document metadata
stateCitations :: M.Map String String, -- ^ RST-style citations
@@ -972,6 +1020,9 @@ class HasReaderOptions st where
-- default
getOption f = (f . extractReaderOptions) <$> getState
+instance HasReaderOptions ParserState where
+ extractReaderOptions = stateOptions
+
class HasQuoteContext st m where
getQuoteContext :: (Stream s m t) => ParsecT s st m QuoteContext
withQuoteContext :: QuoteContext -> ParsecT s st m a -> ParsecT s st m a
@@ -987,9 +1038,6 @@ instance Monad m => HasQuoteContext ParserState m where
setState newState { stateQuoteContext = oldQuoteContext }
return result
-instance HasReaderOptions ParserState where
- extractReaderOptions = stateOptions
-
class HasHeaderMap st where
extractHeaderMap :: st -> M.Map Inlines String
updateHeaderMap :: (M.Map Inlines String -> M.Map Inlines String) ->
@@ -1031,6 +1079,16 @@ instance HasLogMessages ParserState where
addLogMessage msg st = st{ stateLogMessages = msg : stateLogMessages st }
getLogMessages st = reverse $ stateLogMessages st
+class HasIncludeFiles st where
+ getIncludeFiles :: st -> [String]
+ addIncludeFile :: String -> st -> st
+ dropLatestIncludeFile :: st -> st
+
+instance HasIncludeFiles ParserState where
+ getIncludeFiles = stateContainers
+ addIncludeFile f s = s{ stateContainers = f : stateContainers s }
+ dropLatestIncludeFile s = s { stateContainers = drop 1 $ stateContainers s }
+
defaultParserState :: ParserState
defaultParserState =
ParserState { stateOptions = def,
@@ -1043,7 +1101,8 @@ defaultParserState =
stateHeaderKeys = M.empty,
stateSubstitutions = M.empty,
stateNotes = [],
- stateNotes' = [],
+ stateNotes' = M.empty,
+ stateNoteRefs = Set.empty,
stateMeta = nullMeta,
stateMeta' = return nullMeta,
stateCitations = M.empty,
@@ -1110,7 +1169,8 @@ data QuoteContext
type NoteTable = [(String, String)]
-type NoteTable' = [(String, F Blocks)] -- used in markdown reader
+type NoteTable' = M.Map String (SourcePos, F Blocks)
+-- used in markdown reader
newtype Key = Key String deriving (Show, Read, Eq, Ord)
@@ -1322,17 +1382,18 @@ extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
Nothing -> cls
kvs' = filter (\(k,_) -> k /= "id" || k /= "class") kvs
-insertIncludedFile :: PandocMonad m
- => ParserT String ParserState m Blocks
- -> [FilePath] -> FilePath
- -> ParserT String ParserState m Blocks
-insertIncludedFile blocks dirs f = do
+insertIncludedFile' :: (PandocMonad m, HasIncludeFiles st,
+ Functor mf, Applicative mf, Monad mf)
+ => ParserT String st m (mf Blocks)
+ -> [FilePath] -> FilePath
+ -> ParserT String st m (mf Blocks)
+insertIncludedFile' blocks dirs f = do
oldPos <- getPosition
oldInput <- getInput
- containers <- stateContainers <$> getState
+ containers <- getIncludeFiles <$> getState
when (f `elem` containers) $
throwError $ PandocParseError $ "Include file loop at " ++ show oldPos
- updateState $ \s -> s{ stateContainers = f : stateContainers s }
+ updateState $ addIncludeFile f
mbcontents <- readFileFromDirs dirs f
contents <- case mbcontents of
Just s -> return s
@@ -1344,5 +1405,22 @@ insertIncludedFile blocks dirs f = do
bs <- blocks
setInput oldInput
setPosition oldPos
- updateState $ \s -> s{ stateContainers = tail $ stateContainers s }
+ updateState dropLatestIncludeFile
return bs
+
+-- | Parse content of include file as blocks. Circular includes result in an
+-- @PandocParseError@.
+insertIncludedFile :: (PandocMonad m, HasIncludeFiles st)
+ => ParserT String st m Blocks
+ -> [FilePath] -> FilePath
+ -> ParserT String st m Blocks
+insertIncludedFile blocks dirs f =
+ runIdentity <$> insertIncludedFile' (Identity <$> blocks) dirs f
+
+-- | Parse content of include file as future blocks. Circular includes result in
+-- an @PandocParseError@.
+insertIncludedFileF :: (PandocMonad m, HasIncludeFiles st)
+ => ParserT String st m (Future st Blocks)
+ -> [FilePath] -> FilePath
+ -> ParserT String st m (Future st Blocks)
+insertIncludedFileF = insertIncludedFile'
diff --git a/src/Text/Pandoc/Pretty.hs b/src/Text/Pandoc/Pretty.hs
index 32e60843c..d78a2f1d9 100644
--- a/src/Text/Pandoc/Pretty.hs
+++ b/src/Text/Pandoc/Pretty.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE CPP #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2017 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(-1)307 USA
{- |
Module : Text.Pandoc.Pretty
- Copyright : Copyright (C) 2010-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -108,10 +108,10 @@ data D = Text Int String
| CarriageReturn
| NewLine
| BlankLines Int -- number of blank lines
- deriving (Show)
+ deriving (Show, Eq)
newtype Doc = Doc { unDoc :: Seq D }
- deriving (Monoid, Show)
+ deriving (Monoid, Show, Eq)
instance IsString Doc where
fromString = text
diff --git a/src/Text/Pandoc/Process.hs b/src/Text/Pandoc/Process.hs
index 1014f37dd..b2a0c17f1 100644
--- a/src/Text/Pandoc/Process.hs
+++ b/src/Text/Pandoc/Process.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2013-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2013-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Readers.hs b/src/Text/Pandoc/Readers.hs
index e2d40336c..004fefe25 100644
--- a/src/Text/Pandoc/Readers.hs
+++ b/src/Text/Pandoc/Readers.hs
@@ -93,36 +93,37 @@ import Text.Pandoc.Shared (mapLeft)
import Text.Parsec.Error
import qualified Text.Pandoc.UTF8 as UTF8
import qualified Data.ByteString.Lazy as BL
+import Data.Text (Text)
-data Reader m = StringReader (ReaderOptions -> String -> m Pandoc)
+data Reader m = TextReader (ReaderOptions -> Text -> m Pandoc)
| ByteStringReader (ReaderOptions -> BL.ByteString -> m Pandoc)
-- | Association list of formats and readers.
readers :: PandocMonad m => [(String, Reader m)]
-readers = [ ("native" , StringReader readNative)
- ,("json" , StringReader $ \o s ->
+readers = [ ("native" , TextReader readNative)
+ ,("json" , TextReader $ \o s ->
case readJSON o s of
Right doc -> return doc
Left _ -> throwError $ PandocParseError "JSON parse error")
- ,("markdown" , StringReader readMarkdown)
- ,("markdown_strict" , StringReader readMarkdown)
- ,("markdown_phpextra" , StringReader readMarkdown)
- ,("markdown_github" , StringReader readMarkdown)
- ,("markdown_mmd", StringReader readMarkdown)
- ,("commonmark" , StringReader readCommonMark)
- ,("rst" , StringReader readRST)
- ,("mediawiki" , StringReader readMediaWiki)
- ,("docbook" , StringReader readDocBook)
- ,("opml" , StringReader readOPML)
- ,("org" , StringReader readOrg)
- ,("textile" , StringReader readTextile) -- TODO : textile+lhs
- ,("html" , StringReader readHtml)
- ,("latex" , StringReader readLaTeX)
- ,("haddock" , StringReader readHaddock)
- ,("twiki" , StringReader readTWiki)
+ ,("markdown" , TextReader readMarkdown)
+ ,("markdown_strict" , TextReader readMarkdown)
+ ,("markdown_phpextra" , TextReader readMarkdown)
+ ,("markdown_github" , TextReader readMarkdown)
+ ,("markdown_mmd", TextReader readMarkdown)
+ ,("commonmark" , TextReader readCommonMark)
+ ,("rst" , TextReader readRST)
+ ,("mediawiki" , TextReader readMediaWiki)
+ ,("docbook" , TextReader readDocBook)
+ ,("opml" , TextReader readOPML)
+ ,("org" , TextReader readOrg)
+ ,("textile" , TextReader readTextile) -- TODO : textile+lhs
+ ,("html" , TextReader readHtml)
+ ,("latex" , TextReader readLaTeX)
+ ,("haddock" , TextReader readHaddock)
+ ,("twiki" , TextReader readTWiki)
,("docx" , ByteStringReader readDocx)
,("odt" , ByteStringReader readOdt)
- ,("t2t" , StringReader readTxt2Tags)
+ ,("t2t" , TextReader readTxt2Tags)
,("epub" , ByteStringReader readEPUB)
]
@@ -134,7 +135,7 @@ getReader s =
Right (readerName, setExts) ->
case lookup readerName readers of
Nothing -> Left $ "Unknown reader: " ++ readerName
- Just (StringReader r) -> Right $ StringReader $ \o ->
+ Just (TextReader r) -> Right $ TextReader $ \o ->
r o{ readerExtensions = setExts $
getDefaultExtensions readerName }
Just (ByteStringReader r) -> Right $ ByteStringReader $ \o ->
@@ -142,5 +143,6 @@ getReader s =
getDefaultExtensions readerName }
-- | Read pandoc document from JSON format.
-readJSON :: ReaderOptions -> String -> Either PandocError Pandoc
-readJSON _ = mapLeft PandocParseError . eitherDecode' . UTF8.fromStringLazy
+readJSON :: ReaderOptions -> Text -> Either PandocError Pandoc
+readJSON _ =
+ mapLeft PandocParseError . eitherDecode' . BL.fromStrict . UTF8.fromText
diff --git a/src/Text/Pandoc/Readers/CommonMark.hs b/src/Text/Pandoc/Readers/CommonMark.hs
index e98ee066e..3c62f8db5 100644
--- a/src/Text/Pandoc/Readers/CommonMark.hs
+++ b/src/Text/Pandoc/Readers/CommonMark.hs
@@ -34,15 +34,15 @@ where
import CMark
import Data.List (groupBy)
-import Data.Text (pack, unpack)
+import Data.Text (Text, unpack)
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
import Text.Pandoc.Options
-- | Parse a CommonMark formatted string into a 'Pandoc' structure.
-readCommonMark :: PandocMonad m => ReaderOptions -> String -> m Pandoc
+readCommonMark :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
readCommonMark opts s = return $
- nodeToPandoc $ commonmarkToNode opts' $ pack s
+ nodeToPandoc $ commonmarkToNode opts' s
where opts' = if extensionEnabled Ext_smart (readerExtensions opts)
then [optNormalize, optSmart]
else [optNormalize]
diff --git a/src/Text/Pandoc/Readers/DocBook.hs b/src/Text/Pandoc/Readers/DocBook.hs
index bef256a93..bd3c7c356 100644
--- a/src/Text/Pandoc/Readers/DocBook.hs
+++ b/src/Text/Pandoc/Readers/DocBook.hs
@@ -16,6 +16,8 @@ import Text.TeXMath (readMathML, writeTeX)
import Data.Default
import Data.Foldable (asum)
import Text.Pandoc.Class (PandocMonad)
+import Data.Text (Text)
+import qualified Data.Text as T
{-
@@ -522,11 +524,11 @@ instance Default DBState where
, dbContent = [] }
-readDocBook :: PandocMonad m => ReaderOptions -> String -> m Pandoc
+readDocBook :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
readDocBook _ inp = do
- let tree = normalizeTree . parseXML . handleInstructions $ inp
+ let tree = normalizeTree . parseXML . handleInstructions $ T.unpack inp
(bs, st') <- flip runStateT (def{ dbContent = tree }) $ mapM parseBlock $ tree
- return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
+ return $ Pandoc (dbMeta st') (toList . mconcat $ bs)
-- We treat <?asciidoc-br?> specially (issue #1236), converting it
-- to <br/>, since xml-light doesn't parse the instruction correctly.
diff --git a/src/Text/Pandoc/Readers/Docx.hs b/src/Text/Pandoc/Readers/Docx.hs
index 683277993..2757314ab 100644
--- a/src/Text/Pandoc/Readers/Docx.hs
+++ b/src/Text/Pandoc/Readers/Docx.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2017 Jesse Rosenthal <jrosenthal@jhu.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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Docx
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2017 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
diff --git a/src/Text/Pandoc/Readers/Docx/Lists.hs b/src/Text/Pandoc/Readers/Docx/Lists.hs
index 94b4d919a..8be2e1894 100644
--- a/src/Text/Pandoc/Readers/Docx/Lists.hs
+++ b/src/Text/Pandoc/Readers/Docx/Lists.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2017 Jesse Rosenthal <jrosenthal@jhu.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.Docx.Lists
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2017 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs
index 0f23555f4..e6736100f 100644
--- a/src/Text/Pandoc/Readers/Docx/Parse.hs
+++ b/src/Text/Pandoc/Readers/Docx/Parse.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2014-2016 Jesse Rosenthal <jrosenthal@jhu.edu>
+Copyright (C) 2014-2017 Jesse Rosenthal <jrosenthal@jhu.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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Docx.Parse
- Copyright : Copyright (C) 2014-2016 Jesse Rosenthal
+ Copyright : Copyright (C) 2014-2017 Jesse Rosenthal
License : GNU GPL, version 2 or above
Maintainer : Jesse Rosenthal <jrosenthal@jhu.edu>
diff --git a/src/Text/Pandoc/Readers/EPUB.hs b/src/Text/Pandoc/Readers/EPUB.hs
index db58e9654..c0d8029dc 100644
--- a/src/Text/Pandoc/Readers/EPUB.hs
+++ b/src/Text/Pandoc/Readers/EPUB.hs
@@ -13,6 +13,8 @@ import Control.DeepSeq (NFData, deepseq)
import Control.Monad (guard, liftM)
import Control.Monad.Except (throwError)
import qualified Data.ByteString.Lazy as BL (ByteString)
+import qualified Data.Text.Lazy.Encoding as TL
+import qualified Data.Text.Lazy as TL
import Data.List (isInfixOf, isPrefixOf)
import qualified Data.Map as M (Map, elems, fromList, lookup)
import Data.Maybe (fromMaybe, mapMaybe)
@@ -73,7 +75,7 @@ archiveToEPUB os archive = do
mimeToReader "application/xhtml+xml" (unEscapeString -> root)
(unEscapeString -> path) = do
fname <- findEntryByPathE (root </> path) archive
- html <- readHtml os' . UTF8.toStringLazy $ fromEntry fname
+ html <- readHtml os' . TL.toStrict . TL.decodeUtf8 $ fromEntry fname
return $ fixInternalReferences path html
mimeToReader s _ (unEscapeString -> path)
| s `elem` imageMimes = return $ imageToPandoc path
diff --git a/src/Text/Pandoc/Readers/HTML.hs b/src/Text/Pandoc/Readers/HTML.hs
index 14b051539..94f933c4d 100644
--- a/src/Text/Pandoc/Readers/HTML.hs
+++ b/src/Text/Pandoc/Readers/HTML.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE FlexibleContexts, FlexibleInstances, MultiParamTypeClasses,
-ViewPatterns#-}
+ViewPatterns, OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.HTML
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +34,7 @@ module Text.Pandoc.Readers.HTML ( readHtml
, htmlInBalanced
, isInlineTag
, isBlockTag
+ , NamedTag(..)
, isTextTag
, isCommentTag
) where
@@ -43,7 +44,7 @@ import Text.HTML.TagSoup.Match
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', addMetaField
+import Text.Pandoc.Shared ( extractSpaces, addMetaField
, escapeURI, safeRead )
import Text.Pandoc.Options (ReaderOptions(readerExtensions), extensionEnabled,
Extension (Ext_epub_html_exts,
@@ -53,12 +54,14 @@ import Text.Pandoc.Parsing hiding ((<|>))
import Text.Pandoc.Walk
import qualified Data.Map as M
import Data.Maybe ( fromMaybe, isJust)
-import Data.List ( intercalate, isInfixOf, isPrefixOf )
+import Data.List ( intercalate, isPrefixOf )
import Data.Char ( isDigit, isLetter, isAlphaNum )
import Control.Monad ( guard, mzero, void, unless )
import Control.Arrow ((***))
import Control.Applicative ( (<|>) )
import Data.Monoid (First (..))
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.TeXMath (readMathML, writeTeX)
import Data.Default (Default (..), def)
import Control.Monad.Reader (ask, asks, local, ReaderT, runReaderT, lift)
@@ -74,11 +77,12 @@ import Control.Monad.Except (throwError)
-- | Convert HTML-formatted string to 'Pandoc' document.
readHtml :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
-> m Pandoc
readHtml opts inp = do
let tags = stripPrefixes . canonicalizeTags $
- parseTagsOptions parseOptions{ optTagPosition = True } inp
+ parseTagsOptions parseOptions{ optTagPosition = True }
+ inp
parseDoc = do
blocks <- (fixPlains False) . mconcat <$> manyTill block eof
meta <- stateMeta . parserState <$> getState
@@ -128,7 +132,7 @@ setInPlain = local (\s -> s {inPlain = True})
type HTMLParser m s = ParserT s HTMLState (ReaderT HTMLLocal m)
-type TagParser m = HTMLParser m [Tag String]
+type TagParser m = HTMLParser m [Tag Text]
pBody :: PandocMonad m => TagParser m Blocks
pBody = pInTags "body" block
@@ -138,12 +142,12 @@ 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
- mt <- pSatisfy (~== TagOpen "meta" [])
- let name = fromAttrib "name" mt
+ mt <- pSatisfy (matchTagOpen "meta" [])
+ let name = T.unpack $ fromAttrib "name" mt
if null name
then return mempty
else do
- let content = fromAttrib "content" mt
+ let content = T.unpack $ fromAttrib "content" mt
updateState $ \s ->
let ps = parserState s in
s{ parserState = ps{
@@ -151,9 +155,9 @@ pHead = pInTags "head" $ pTitle <|> pMetaTag <|> pBaseTag <|> (mempty <$ pAnyTag
(stateMeta ps) } }
return mempty
pBaseTag = do
- bt <- pSatisfy (~== TagOpen "base" [])
+ bt <- pSatisfy (matchTagOpen "base" [])
updateState $ \st -> st{ baseHref =
- parseURIReference $ fromAttrib "href" bt }
+ parseURIReference $ T.unpack $ fromAttrib "href" bt }
return mempty
block :: PandocMonad m => TagParser m Blocks
@@ -193,29 +197,31 @@ eSwitch :: (PandocMonad m, Monoid a)
-> TagParser m a
eSwitch constructor parser = try $ do
guardEnabled Ext_epub_html_exts
- pSatisfy (~== TagOpen "switch" [])
+ pSatisfy (matchTagOpen "switch" [])
cases <- getFirst . mconcat <$>
manyTill (First <$> (eCase <* skipMany pBlank) )
- (lookAhead $ try $ pSatisfy (~== TagOpen "default" []))
+ (lookAhead $ try $ pSatisfy (matchTagOpen "default" []))
skipMany pBlank
fallback <- pInTags "default" (skipMany pBlank *> parser <* skipMany pBlank)
skipMany pBlank
- pSatisfy (~== TagClose "switch")
+ pSatisfy (matchTagClose "switch")
return $ maybe fallback constructor cases
eCase :: PandocMonad m => TagParser m (Maybe Inlines)
eCase = do
skipMany pBlank
- TagOpen _ attr <- lookAhead $ pSatisfy $ (~== TagOpen "case" [])
+ TagOpen _ attr' <- lookAhead $ pSatisfy $ (matchTagOpen "case" [])
+ let attr = toStringAttr attr'
case (flip lookup namespaces) =<< lookup "required-namespace" attr of
Just p -> Just <$> (pInTags "case" (skipMany pBlank *> p <* skipMany pBlank))
- Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (~== TagClose "case"))
+ Nothing -> Nothing <$ manyTill pAnyTag (pSatisfy (matchTagClose "case"))
eFootnote :: PandocMonad m => TagParser m ()
eFootnote = try $ do
let notes = ["footnote", "rearnote"]
guardEnabled Ext_epub_html_exts
- (TagOpen tag attr) <- lookAhead $ pAnyTag
+ (TagOpen tag attr') <- lookAhead $ pAnyTag
+ let attr = toStringAttr attr'
guard (maybe False (flip elem notes) (lookup "type" attr))
let ident = fromMaybe "" (lookup "id" attr)
content <- pInTags tag block
@@ -227,7 +233,8 @@ addNote uid cont = updateState (\s -> s {noteTable = (uid, cont) : (noteTable s)
eNoteref :: PandocMonad m => TagParser m Inlines
eNoteref = try $ do
guardEnabled Ext_epub_html_exts
- TagOpen tag attr <- lookAhead $ pAnyTag
+ TagOpen tag attr' <- lookAhead $ pAnyTag
+ let attr = toStringAttr attr'
guard (maybe False (== "noteref") (lookup "type" attr))
let ident = maybe "" (dropWhile (== '#')) (lookup "href" attr)
guard (not (null ident))
@@ -247,10 +254,10 @@ pList = pBulletList <|> pOrderedList <|> pDefinitionList
pBulletList :: PandocMonad m => TagParser m Blocks
pBulletList = try $ do
- pSatisfy (~== TagOpen "ul" [])
+ pSatisfy (matchTagOpen "ul" [])
let nonItem = pSatisfy (\t ->
not (tagOpen (`elem` ["li","ol","ul","dl"]) (const True) t) &&
- not (t ~== TagClose "ul"))
+ not (matchTagClose "ul" t))
-- note: if they have an <ol> or <ul> not in scope of a <li>,
-- treat it as a list item, though it's not valid xhtml...
skipMany nonItem
@@ -259,7 +266,8 @@ pBulletList = try $ do
pListItem :: PandocMonad m => TagParser m a -> TagParser m Blocks
pListItem nonItem = do
- TagOpen _ attr <- lookAhead $ pSatisfy (~== TagOpen "li" [])
+ TagOpen _ attr' <- lookAhead $ pSatisfy (matchTagOpen "li" [])
+ let attr = toStringAttr attr'
let addId ident bs = case B.toList bs of
(Plain ils:xs) -> B.fromList (Plain
[Span (ident, [], []) ils] : xs)
@@ -285,7 +293,8 @@ parseTypeAttr _ = DefaultStyle
pOrderedList :: PandocMonad m => TagParser m Blocks
pOrderedList = try $ do
- TagOpen _ attribs <- pSatisfy (~== TagOpen "ol" [])
+ TagOpen _ attribs' <- pSatisfy (matchTagOpen "ol" [])
+ let attribs = toStringAttr attribs'
let (start, style) = (sta', sty')
where sta = fromMaybe "1" $
lookup "start" attribs
@@ -307,7 +316,7 @@ pOrderedList = try $ do
]
let nonItem = pSatisfy (\t ->
not (tagOpen (`elem` ["li","ol","ul","dl"]) (const True) t) &&
- not (t ~== TagClose "ol"))
+ not (matchTagClose "ol" t))
-- note: if they have an <ol> or <ul> not in scope of a <li>,
-- treat it as a list item, though it's not valid xhtml...
skipMany nonItem
@@ -316,14 +325,14 @@ pOrderedList = try $ do
pDefinitionList :: PandocMonad m => TagParser m Blocks
pDefinitionList = try $ do
- pSatisfy (~== TagOpen "dl" [])
+ pSatisfy (matchTagOpen "dl" [])
items <- manyTill pDefListItem (pCloses "dl")
return $ B.definitionList items
pDefListItem :: PandocMonad m => TagParser m (Inlines, [Blocks])
pDefListItem = try $ do
- let nonItem = pSatisfy (\t -> not (t ~== TagOpen "dt" []) &&
- not (t ~== TagOpen "dd" []) && not (t ~== TagClose "dl"))
+ let nonItem = pSatisfy (\t -> not (matchTagOpen "dt" [] t) &&
+ not (matchTagOpen "dd" [] t) && not (matchTagClose "dl" t))
terms <- many1 (try $ skipMany nonItem >> pInTags "dt" inline)
defs <- many1 (try $ skipMany nonItem >> pInTags "dd" block)
skipMany nonItem
@@ -346,12 +355,12 @@ fixPlains inList bs = if any isParaish bs'
plainToPara x = x
bs' = B.toList bs
-pRawTag :: PandocMonad m => TagParser m String
+pRawTag :: PandocMonad m => TagParser m Text
pRawTag = do
tag <- pAnyTag
let ignorable x = x `elem` ["html","head","body","!DOCTYPE","?xml"]
if tagOpen ignorable (const True) tag || tagClose ignorable tag
- then return []
+ then return mempty
else return $ renderTags' [tag]
pDiv :: PandocMonad m => TagParser m Blocks
@@ -360,7 +369,8 @@ pDiv = try $ do
let isDivLike "div" = True
isDivLike "section" = True
isDivLike _ = False
- TagOpen tag attr <- lookAhead $ pSatisfy $ tagOpen isDivLike (const True)
+ TagOpen tag attr' <- lookAhead $ pSatisfy $ tagOpen isDivLike (const True)
+ let attr = toStringAttr attr'
contents <- pInTags tag block
let (ident, classes, kvs) = mkAttr attr
let classes' = if tag == "section"
@@ -370,7 +380,7 @@ pDiv = try $ do
pRawHtmlBlock :: PandocMonad m => TagParser m Blocks
pRawHtmlBlock = do
- raw <- pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag
+ raw <- T.unpack <$> (pHtmlBlock "script" <|> pHtmlBlock "style" <|> pRawTag)
exts <- getOption readerExtensions
if extensionEnabled Ext_raw_html exts && not (null raw)
then return $ B.rawBlock "html" raw
@@ -385,33 +395,35 @@ ignore raw = do
logMessage $ SkippedContent raw pos
return mempty
-pHtmlBlock :: PandocMonad m => String -> TagParser m String
+pHtmlBlock :: PandocMonad m => Text -> TagParser m Text
pHtmlBlock t = try $ do
- open <- pSatisfy (~== TagOpen t [])
- contents <- manyTill pAnyTag (pSatisfy (~== TagClose t))
- return $ renderTags' $ [open] ++ contents ++ [TagClose t]
+ open <- pSatisfy (matchTagOpen t [])
+ contents <- manyTill pAnyTag (pSatisfy (matchTagClose t))
+ return $ renderTags' $ [open] <> contents <> [TagClose t]
-- Sets chapter context
eSection :: PandocMonad m => TagParser m Blocks
eSection = try $ do
- let matchChapter as = maybe False (isInfixOf "chapter") (lookup "type" as)
+ let matchChapter as = maybe False (T.isInfixOf "chapter") (lookup "type" as)
let sectTag = tagOpen (`elem` sectioningContent) matchChapter
TagOpen tag _ <- lookAhead $ pSatisfy sectTag
setInChapter (pInTags tag block)
-headerLevel :: PandocMonad m => String -> TagParser m Int
+headerLevel :: PandocMonad m => Text -> TagParser m Int
headerLevel tagtype = do
- let level = read (drop 1 tagtype)
- (try $ do
- guardEnabled Ext_epub_html_exts
- asks inChapter >>= guard
- return (level - 1))
- <|>
- return level
+ case safeRead (T.unpack (T.drop 1 tagtype)) of
+ Just level ->
+ (try $ do
+ guardEnabled Ext_epub_html_exts
+ asks inChapter >>= guard
+ return (level - 1))
+ <|>
+ return level
+ Nothing -> fail "Could not retrieve header level"
eTitlePage :: PandocMonad m => TagParser m ()
eTitlePage = try $ do
- let isTitlePage as = maybe False (isInfixOf "titlepage") (lookup "type" as)
+ let isTitlePage as = maybe False (T.isInfixOf "titlepage") (lookup "type" as)
let groupTag = tagOpen (\x -> x `elem` groupingContent || x == "section")
isTitlePage
TagOpen tag _ <- lookAhead $ pSatisfy groupTag
@@ -419,19 +431,21 @@ eTitlePage = try $ do
pHeader :: PandocMonad m => TagParser m Blocks
pHeader = try $ do
- TagOpen tagtype attr <- pSatisfy $
+ TagOpen tagtype attr' <- pSatisfy $
tagOpen (`elem` ["h1","h2","h3","h4","h5","h6"])
(const True)
- let bodyTitle = TagOpen tagtype attr ~== TagOpen "h1" [("class","title")]
+ let attr = toStringAttr attr'
+ let bodyTitle = TagOpen tagtype attr' ~== TagOpen ("h1" :: Text)
+ [("class","title")]
level <- headerLevel tagtype
contents <- trimInlines . mconcat <$> manyTill inline (pCloses tagtype <|> eof)
let ident = fromMaybe "" $ lookup "id" attr
let classes = maybe [] words $ lookup "class" attr
let keyvals = [(k,v) | (k,v) <- attr, k /= "class", k /= "id"]
- attr' <- registerHeader (ident, classes, keyvals) contents
+ attr'' <- registerHeader (ident, classes, keyvals) contents
return $ if bodyTitle
then mempty -- skip a representation of the title in the body
- else B.headerWith attr' level contents
+ else B.headerWith attr'' level contents
pHrule :: PandocMonad m => TagParser m Blocks
pHrule = do
@@ -440,7 +454,7 @@ pHrule = do
pTable :: PandocMonad m => TagParser m Blocks
pTable = try $ do
- TagOpen _ _ <- pSatisfy (~== TagOpen "table" [])
+ TagOpen _ _ <- pSatisfy (matchTagOpen "table" [])
skipMany pBlank
caption <- option mempty $ pInTags "caption" inline <* skipMany pBlank
widths' <- (mconcat <$> many1 pColgroup) <|> many pCol
@@ -454,8 +468,8 @@ pTable = try $ do
else return head''
rowsLs <- many pTBody
rows' <- pOptInTag "tfoot" $ many pTr
- TagClose _ <- pSatisfy (~== TagClose "table")
- let rows'' = (concat rowsLs) ++ rows'
+ TagClose _ <- pSatisfy (matchTagClose "table")
+ let rows'' = (concat rowsLs) <> rows'
-- fail on empty table
guard $ not $ null head' && null rows''
let isSinglePlain x = case B.toList x of
@@ -466,7 +480,7 @@ pTable = try $ do
let cols = length $ if null head' then head rows'' else head'
-- add empty cells to short rows
let addEmpties r = case cols - length r of
- n | n > 0 -> r ++ replicate n mempty
+ n | n > 0 -> r <> replicate n mempty
| otherwise -> r
let rows = map addEmpties rows''
let aligns = replicate cols AlignDefault
@@ -479,15 +493,16 @@ pTable = try $ do
pCol :: PandocMonad m => TagParser m Double
pCol = try $ do
- TagOpen _ attribs <- pSatisfy (~== TagOpen "col" [])
+ TagOpen _ attribs' <- pSatisfy (matchTagOpen "col" [])
+ let attribs = toStringAttr attribs'
skipMany pBlank
- optional $ pSatisfy (~== TagClose "col")
+ optional $ pSatisfy (matchTagClose "col")
skipMany pBlank
return $ case lookup "width" attribs of
Nothing -> case lookup "style" attribs of
Just ('w':'i':'d':'t':'h':':':xs) | '%' `elem` xs ->
fromMaybe 0.0 $ safeRead ('0':'.':filter
- (`notElem` " \t\r\n%'\";") xs)
+ (`notElem` (" \t\r\n%'\";" :: [Char])) xs)
_ -> 0.0
Just x | not (null x) && last x == '%' ->
fromMaybe 0.0 $ safeRead ('0':'.':init x)
@@ -495,18 +510,18 @@ pCol = try $ do
pColgroup :: PandocMonad m => TagParser m [Double]
pColgroup = try $ do
- pSatisfy (~== TagOpen "colgroup" [])
+ pSatisfy (matchTagOpen "colgroup" [])
skipMany pBlank
manyTill pCol (pCloses "colgroup" <|> eof) <* skipMany pBlank
-noColOrRowSpans :: Tag String -> Bool
+noColOrRowSpans :: Tag Text -> Bool
noColOrRowSpans t = isNullOrOne "colspan" && isNullOrOne "rowspan"
where isNullOrOne x = case fromAttrib x t of
"" -> True
"1" -> True
_ -> False
-pCell :: PandocMonad m => String -> TagParser m [Blocks]
+pCell :: PandocMonad m => Text -> TagParser m [Blocks]
pCell celltype = try $ do
skipMany pBlank
res <- pInTags' celltype noColOrRowSpans block
@@ -532,7 +547,8 @@ pPara = do
pCodeBlock :: PandocMonad m => TagParser m Blocks
pCodeBlock = try $ do
- TagOpen _ attr <- pSatisfy (~== TagOpen "pre" [])
+ TagOpen _ attr' <- pSatisfy (matchTagOpen "pre" [])
+ let attr = toStringAttr attr'
contents <- manyTill pAnyTag (pCloses "pre" <|> eof)
let rawText = concatMap tagToString contents
-- drop leading newline if any
@@ -545,8 +561,8 @@ pCodeBlock = try $ do
_ -> result'
return $ B.codeBlockWith (mkAttr attr) result
-tagToString :: Tag String -> String
-tagToString (TagText s) = s
+tagToString :: Tag Text -> String
+tagToString (TagText s) = T.unpack s
tagToString (TagOpen "br" _) = "\n"
tagToString _ = ""
@@ -575,20 +591,20 @@ pLocation = do
(TagPosition r c) <- pSat isTagPosition
setPosition $ newPos "input" r c
-pSat :: PandocMonad m => (Tag String -> Bool) -> TagParser m (Tag String)
+pSat :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSat f = do
pos <- getPosition
token show (const pos) (\x -> if f x then Just x else Nothing)
-pSatisfy :: PandocMonad m => (Tag String -> Bool) -> TagParser m (Tag String)
+pSatisfy :: PandocMonad m => (Tag Text -> Bool) -> TagParser m (Tag Text)
pSatisfy f = try $ optional pLocation >> pSat f
-pAnyTag :: PandocMonad m => TagParser m (Tag String)
+pAnyTag :: PandocMonad m => TagParser m (Tag Text)
pAnyTag = pSatisfy (const True)
pSelfClosing :: PandocMonad m
- => (String -> Bool) -> ([Attribute String] -> Bool)
- -> TagParser m (Tag String)
+ => (Text -> Bool) -> ([Attribute Text] -> Bool)
+ -> TagParser m (Tag Text)
pSelfClosing f g = do
open <- pSatisfy (tagOpen f g)
optional $ pSatisfy (tagClose f)
@@ -626,7 +642,7 @@ pStrikeout = do
pInlinesInTags "s" B.strikeout <|>
pInlinesInTags "strike" B.strikeout <|>
pInlinesInTags "del" B.strikeout <|>
- try (do pSatisfy (~== TagOpen "span" [("class","strikeout")])
+ try (do pSatisfy (matchTagOpen "span" [("class","strikeout")])
contents <- mconcat <$> manyTill inline (pCloses "span")
return $ B.strikeout contents)
@@ -637,17 +653,19 @@ pLineBreak = do
-- Unlike fromAttrib from tagsoup, this distinguishes
-- between a missing attribute and an attribute with empty content.
-maybeFromAttrib :: String -> Tag String -> Maybe String
-maybeFromAttrib name (TagOpen _ attrs) = lookup name attrs
+maybeFromAttrib :: String -> Tag Text -> Maybe String
+maybeFromAttrib name (TagOpen _ attrs) =
+ T.unpack <$> lookup (T.pack name) attrs
maybeFromAttrib _ _ = Nothing
pLink :: PandocMonad m => TagParser m Inlines
pLink = try $ do
tag <- pSatisfy $ tagOpenLit "a" (const True)
- let title = fromAttrib "title" tag
+ let title = T.unpack $ fromAttrib "title" tag
-- take id from id attribute if present, otherwise name
- let uid = maybe (fromAttrib "name" tag) id $ maybeFromAttrib "id" tag
- let cls = words $ fromAttrib "class" tag
+ let uid = maybe (T.unpack $ fromAttrib "name" tag) id $
+ maybeFromAttrib "id" tag
+ let cls = words $ T.unpack $ fromAttrib "class" tag
lab <- trimInlines . mconcat <$> manyTill inline (pCloses "a")
-- check for href; if href, then a link, otherwise a span
case maybeFromAttrib "href" tag of
@@ -665,30 +683,33 @@ pImage :: PandocMonad m => TagParser m Inlines
pImage = do
tag <- pSelfClosing (=="img") (isJust . lookup "src")
mbBaseHref <- baseHref <$> getState
- let url' = fromAttrib "src" tag
+ let url' = T.unpack $ fromAttrib "src" tag
let url = case (parseURIReference url', mbBaseHref) of
(Just rel, Just bs) -> show (rel `nonStrictRelativeTo` bs)
_ -> url'
- let title = fromAttrib "title" tag
- let alt = fromAttrib "alt" tag
- let uid = fromAttrib "id" tag
- let cls = words $ fromAttrib "class" tag
+ let title = T.unpack $ fromAttrib "title" tag
+ let alt = T.unpack $ fromAttrib "alt" tag
+ let uid = T.unpack $ fromAttrib "id" tag
+ let cls = words $ T.unpack $ fromAttrib "class" tag
let getAtt k = case fromAttrib k tag of
"" -> []
- v -> [(k, v)]
+ v -> [(T.unpack k, T.unpack v)]
let kvs = concat $ map getAtt ["width", "height", "sizes", "srcset"]
return $ B.imageWith (uid, cls, kvs) (escapeURI url) title (B.text alt)
pCode :: PandocMonad m => TagParser m Inlines
pCode = try $ do
- (TagOpen open attr) <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
+ (TagOpen open attr') <- pSatisfy $ tagOpen (`elem` ["code","tt"]) (const True)
+ let attr = toStringAttr attr'
result <- manyTill pAnyTag (pCloses open)
- return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ innerText result
+ return $ B.codeWith (mkAttr attr) $ intercalate " " $ lines $ T.unpack $
+ innerText result
pSpan :: PandocMonad m => TagParser m Inlines
pSpan = try $ do
guardEnabled Ext_native_spans
- TagOpen _ attr <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
+ TagOpen _ attr' <- lookAhead $ pSatisfy $ tagOpen (=="span") (const True)
+ let attr = toStringAttr attr'
contents <- pInTags "span" inline
let isSmallCaps = fontVariant == "small-caps" || "smallcaps" `elem` classes
where styleAttr = fromMaybe "" $ lookup "style" attr
@@ -706,7 +727,7 @@ pRawHtmlInline = do
then pSatisfy (not . isBlockTag)
else pSatisfy isInlineTag
exts <- getOption readerExtensions
- let raw = renderTags' [result]
+ let raw = T.unpack $ renderTags' [result]
if extensionEnabled Ext_raw_html exts
then return $ B.rawInline "html" raw
else ignore raw
@@ -714,32 +735,38 @@ pRawHtmlInline = do
mathMLToTeXMath :: String -> Either String String
mathMLToTeXMath s = writeTeX <$> readMathML s
+toStringAttr :: [(Text, Text)] -> [(String, String)]
+toStringAttr = map go
+ where go (x,y) = (T.unpack x, T.unpack y)
+
pMath :: PandocMonad m => Bool -> TagParser m Inlines
pMath inCase = try $ do
- open@(TagOpen _ attr) <- pSatisfy $ tagOpen (=="math") (const True)
+ open@(TagOpen _ attr') <- pSatisfy $ tagOpen (=="math") (const True)
-- we'll assume math tags are MathML unless specially marked
-- otherwise...
+ let attr = toStringAttr attr'
unless inCase $
guard (maybe True (== mathMLNamespace) (lookup "xmlns" attr))
- contents <- manyTill pAnyTag (pSatisfy (~== TagClose "math"))
- case mathMLToTeXMath (renderTags $ [open] ++ contents ++ [TagClose "math"]) of
+ contents <- manyTill pAnyTag (pSatisfy (matchTagClose "math"))
+ case mathMLToTeXMath (T.unpack $ renderTags $
+ [open] <> contents <> [TagClose "math"]) of
Left _ -> return $ B.spanWith ("",["math"],attr) $ B.text $
- innerText contents
+ T.unpack $ innerText contents
Right [] -> return mempty
Right x -> return $ case lookup "display" attr of
Just "block" -> B.displayMath x
_ -> B.math x
-pInlinesInTags :: PandocMonad m => String -> (Inlines -> Inlines)
+pInlinesInTags :: PandocMonad m => Text -> (Inlines -> Inlines)
-> TagParser m Inlines
pInlinesInTags tagtype f = extractSpaces f <$> pInTags tagtype inline
-pInTags :: (PandocMonad m, Monoid a) => String -> TagParser m a -> TagParser m a
+pInTags :: (PandocMonad m, Monoid a) => Text -> TagParser m a -> TagParser m a
pInTags tagtype parser = pInTags' tagtype (const True) parser
pInTags' :: (PandocMonad m, Monoid a)
- => String
- -> (Tag String -> Bool)
+ => Text
+ -> (Tag Text -> Bool)
-> TagParser m a
-> TagParser m a
pInTags' tagtype tagtest parser = try $ do
@@ -748,18 +775,18 @@ pInTags' tagtype tagtest parser = try $ do
-- parses p, preceeded by an optional opening tag
-- and followed by an optional closing tags
-pOptInTag :: PandocMonad m => String -> TagParser m a -> TagParser m a
+pOptInTag :: PandocMonad m => Text -> TagParser m a -> TagParser m a
pOptInTag tagtype p = try $ do
skipMany pBlank
- optional $ pSatisfy (~== TagOpen tagtype [])
+ optional $ pSatisfy (matchTagOpen tagtype [])
skipMany pBlank
x <- p
skipMany pBlank
- optional $ pSatisfy (~== TagClose tagtype)
+ optional $ pSatisfy (matchTagClose tagtype)
skipMany pBlank
return x
-pCloses :: PandocMonad m => String -> TagParser m ()
+pCloses :: PandocMonad m => Text -> TagParser m ()
pCloses tagtype = try $ do
t <- lookAhead $ pSatisfy $ \tag -> isTagClose tag || isTagOpen tag
case t of
@@ -780,15 +807,15 @@ pTagText = try $ do
parsed <- lift $ lift $
flip runReaderT qu $ runParserT (many pTagContents) st "text" str
case parsed of
- Left _ -> throwError $ PandocParseError $ "Could not parse `" ++ str ++ "'"
+ Left _ -> throwError $ PandocParseError $ "Could not parse `" <> T.unpack str <> "'"
Right result -> return $ mconcat result
pBlank :: PandocMonad m => TagParser m ()
pBlank = try $ do
(TagText str) <- pSatisfy isTagText
- guard $ all isSpace str
+ guard $ T.all isSpace str
-type InlinesParser m = HTMLParser m String
+type InlinesParser m = HTMLParser m Text
pTagContents :: PandocMonad m => InlinesParser m Inlines
pTagContents =
@@ -869,80 +896,89 @@ pSpace = many1 (satisfy isSpace) >>= \xs ->
-- Constants
--
-eitherBlockOrInline :: [String]
-eitherBlockOrInline = ["audio", "applet", "button", "iframe", "embed",
- "del", "ins",
- "progress", "map", "area", "noscript", "script",
- "object", "svg", "video", "source"]
-
-{-
-inlineHtmlTags :: [[Char]]
-inlineHtmlTags = ["a", "abbr", "acronym", "b", "basefont", "bdo", "big",
- "br", "cite", "code", "dfn", "em", "font", "i", "img",
- "input", "kbd", "label", "q", "s", "samp", "select",
- "small", "span", "strike", "strong", "sub", "sup",
- "textarea", "tt", "u", "var"]
--}
-
-blockHtmlTags :: [String]
-blockHtmlTags = ["?xml", "!DOCTYPE", "address", "article", "aside",
- "blockquote", "body", "button", "canvas",
- "caption", "center", "col", "colgroup", "dd", "dir", "div",
- "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",
- "section", "table", "tbody", "textarea",
- "thead", "tfoot", "ul", "dd",
- "dt", "frameset", "li", "tbody", "td", "tfoot",
- "th", "thead", "tr", "script", "style"]
+eitherBlockOrInline :: Set.Set Text
+eitherBlockOrInline = Set.fromList
+ ["audio", "applet", "button", "iframe", "embed",
+ "del", "ins", "progress", "map", "area", "noscript", "script",
+ "object", "svg", "video", "source"]
+
+blockHtmlTags :: Set.Set Text
+blockHtmlTags = Set.fromList
+ ["?xml", "!DOCTYPE", "address", "article", "aside",
+ "blockquote", "body", "canvas",
+ "caption", "center", "col", "colgroup", "dd", "details",
+ "dir", "div", "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",
+ "section", "table", "tbody", "textarea",
+ "thead", "tfoot", "ul", "dd",
+ "dt", "frameset", "li", "tbody", "td", "tfoot",
+ "th", "thead", "tr", "script", "style"]
-- We want to allow raw docbook in markdown documents, so we
-- include docbook block tags here too.
-blockDocBookTags :: [String]
-blockDocBookTags = ["calloutlist", "bibliolist", "glosslist", "itemizedlist",
- "orderedlist", "segmentedlist", "simplelist",
- "variablelist", "caution", "important", "note", "tip",
- "warning", "address", "literallayout", "programlisting",
- "programlistingco", "screen", "screenco", "screenshot",
- "synopsis", "example", "informalexample", "figure",
- "informalfigure", "table", "informaltable", "para",
- "simpara", "formalpara", "equation", "informalequation",
- "figure", "screenshot", "mediaobject", "qandaset",
- "procedure", "task", "cmdsynopsis", "funcsynopsis",
- "classsynopsis", "blockquote", "epigraph", "msgset",
- "sidebar", "title"]
-
-epubTags :: [String]
-epubTags = ["case", "switch", "default"]
-
-blockTags :: [String]
-blockTags = blockHtmlTags ++ blockDocBookTags ++ epubTags
-
-isInlineTag :: Tag String -> Bool
-isInlineTag t = tagOpen isInlineTagName (const True) t ||
- tagClose isInlineTagName t ||
- tagComment (const True) t
- where isInlineTagName x = x `notElem` blockTags
-
-isBlockTag :: Tag String -> Bool
-isBlockTag t = tagOpen isBlockTagName (const True) t ||
- tagClose isBlockTagName t ||
- tagComment (const True) t
- where isBlockTagName ('?':_) = True
- isBlockTagName ('!':_) = True
- isBlockTagName x = x `elem` blockTags
- || x `elem` eitherBlockOrInline
-
-isTextTag :: Tag String -> Bool
+blockDocBookTags :: Set.Set Text
+blockDocBookTags = Set.fromList
+ ["calloutlist", "bibliolist", "glosslist", "itemizedlist",
+ "orderedlist", "segmentedlist", "simplelist",
+ "variablelist", "caution", "important", "note", "tip",
+ "warning", "address", "literallayout", "programlisting",
+ "programlistingco", "screen", "screenco", "screenshot",
+ "synopsis", "example", "informalexample", "figure",
+ "informalfigure", "table", "informaltable", "para",
+ "simpara", "formalpara", "equation", "informalequation",
+ "figure", "screenshot", "mediaobject", "qandaset",
+ "procedure", "task", "cmdsynopsis", "funcsynopsis",
+ "classsynopsis", "blockquote", "epigraph", "msgset",
+ "sidebar", "title"]
+
+epubTags :: Set.Set Text
+epubTags = Set.fromList ["case", "switch", "default"]
+
+blockTags :: Set.Set Text
+blockTags = Set.unions [blockHtmlTags, blockDocBookTags, epubTags]
+
+class NamedTag a where
+ getTagName :: a -> Maybe Text
+
+instance NamedTag (Tag Text) where
+ getTagName (TagOpen t _) = Just t
+ getTagName (TagClose t) = Just t
+ getTagName _ = Nothing
+
+instance NamedTag (Tag String) where
+ getTagName (TagOpen t _) = Just (T.pack t)
+ getTagName (TagClose t) = Just (T.pack t)
+ getTagName _ = Nothing
+
+isInlineTag :: NamedTag (Tag a) => Tag a -> Bool
+isInlineTag t = isInlineTagName || isCommentTag t
+ where isInlineTagName = case getTagName t of
+ Just x -> x
+ `Set.notMember` blockTags
+ Nothing -> False
+
+isBlockTag :: NamedTag (Tag a) => Tag a -> Bool
+isBlockTag t = isBlockTagName || isTagComment t
+ where isBlockTagName =
+ case getTagName t of
+ Just x
+ | "?" `T.isPrefixOf` x -> True
+ | "!" `T.isPrefixOf` x -> True
+ | otherwise -> x `Set.member` blockTags
+ || x `Set.member` eitherBlockOrInline
+ Nothing -> False
+
+isTextTag :: Tag a -> Bool
isTextTag = tagText (const True)
-isCommentTag :: Tag String -> Bool
+isCommentTag :: Tag a -> Bool
isCommentTag = tagComment (const True)
-- taken from HXT and extended
-- See http://www.w3.org/TR/html5/syntax.html sec 8.1.2.4 optional tags
-closes :: String -> String -> Bool
+closes :: Text -> Text -> Bool
_ `closes` "body" = False
_ `closes` "html" = False
"body" `closes` "head" = True
@@ -975,8 +1011,9 @@ t `closes` t2 |
t `elem` ["h1","h2","h3","h4","h5","h6","dl","ol","ul","table","div","p"] &&
t2 `elem` ["h1","h2","h3","h4","h5","h6","p" ] = True -- not "div"
t1 `closes` t2 |
- t1 `elem` blockTags &&
- t2 `notElem` (blockTags ++ eitherBlockOrInline) = True
+ t1 `Set.member` blockTags &&
+ t2 `Set.notMember` blockTags &&
+ t2 `Set.notMember` eitherBlockOrInline = True
_ `closes` _ = False
--- parsers for use in markdown, textile readers
@@ -1003,8 +1040,11 @@ htmlInBalanced f = try $ do
let cs = ec - sc
lscontents <- unlines <$> count ls anyLine
cscontents <- count cs anyChar
- (_,closetag) <- htmlTag (~== TagClose tn)
- return (lscontents ++ cscontents ++ closetag)
+ closetag <- do
+ x <- many (satisfy (/='>'))
+ char '>'
+ return (x <> ">")
+ return (lscontents <> cscontents <> closetag)
_ -> mzero
_ -> mzero
@@ -1022,7 +1062,7 @@ htmlInBalanced' tagname ts = fromMaybe [] $ go 0 ts
go n (t:ts') = (t :) <$> go n ts'
go _ [] = mzero
-hasTagWarning :: [Tag String] -> Bool
+hasTagWarning :: [Tag a] -> Bool
hasTagWarning (TagWarning _:_) = True
hasTagWarning _ = False
@@ -1050,47 +1090,48 @@ htmlTag f = try $ do
-- basic sanity check, since the parser is very forgiving
-- and finds tags in stuff like x<y)
guard $ isName tagname
+ guard $ not $ null tagname
-- <https://example.org> should NOT be a tag either.
-- tagsoup will parse it as TagOpen "https:" [("example.org","")]
guard $ last tagname /= ':'
rendered <- manyTill anyChar (char '>')
- return (next, rendered ++ ">")
+ return (next, rendered <> ">")
case next of
TagComment s
| "<!--" `isPrefixOf` inp -> do
count (length s + 4) anyChar
skipMany (satisfy (/='>'))
char '>'
- return (next, "<!--" ++ s ++ "-->")
+ return (next, "<!--" <> s <> "-->")
| otherwise -> fail "bogus comment mode, HTML5 parse error"
TagOpen tagname attr -> do
guard $ all (isName . fst) attr
handleTag tagname
- TagClose tagname -> handleTag tagname
+ TagClose tagname ->
+ handleTag tagname
_ -> mzero
mkAttr :: [(String, String)] -> Attr
mkAttr attr = (attribsId, attribsClasses, attribsKV)
where attribsId = fromMaybe "" $ lookup "id" attr
- attribsClasses = (words $ fromMaybe "" $ lookup "class" attr) ++ epubTypes
+ attribsClasses = (words $ fromMaybe "" $ lookup "class" attr) <> epubTypes
attribsKV = filter (\(k,_) -> k /= "class" && k /= "id") attr
epubTypes = words $ fromMaybe "" $ lookup "epub:type" attr
-- Strip namespace prefixes
-stripPrefixes :: [Tag String] -> [Tag String]
+stripPrefixes :: [Tag Text] -> [Tag Text]
stripPrefixes = map stripPrefix
-stripPrefix :: Tag String -> Tag String
+stripPrefix :: Tag Text -> Tag Text
stripPrefix (TagOpen s as) =
TagOpen (stripPrefix' s) (map (stripPrefix' *** id) as)
stripPrefix (TagClose s) = TagClose (stripPrefix' s)
stripPrefix x = x
-stripPrefix' :: String -> String
+stripPrefix' :: Text -> Text
stripPrefix' s =
- case span (/= ':') s of
- (_, "") -> s
- (_, (_:ts)) -> ts
+ if T.null t then s else T.drop 1 t
+ where (_, t) = T.span (/= ':') s
isSpace :: Char -> Bool
isSpace ' ' = True
@@ -1133,19 +1174,32 @@ instance HasLastStrPosition HTMLState where
setLastStrPos s st = st {parserState = setLastStrPos s (parserState st)}
getLastStrPos = getLastStrPos . parserState
+-- For now we need a special verison here; the one in Shared has String type
+renderTags' :: [Tag Text] -> Text
+renderTags' = renderTagsOptions
+ renderOptions{ optMinimize = matchTags ["hr", "br", "img",
+ "meta", "link"]
+ , optRawTag = matchTags ["script", "style"] }
+ where matchTags = \tags -> flip elem tags . T.toLower
+
-- EPUB Specific
--
--
-sectioningContent :: [String]
+sectioningContent :: [Text]
sectioningContent = ["article", "aside", "nav", "section"]
-groupingContent :: [String]
+groupingContent :: [Text]
groupingContent = ["p", "hr", "pre", "blockquote", "ol"
, "ul", "li", "dl", "dt", "dt", "dd"
, "figure", "figcaption", "div", "main"]
+matchTagClose :: Text -> (Tag Text -> Bool)
+matchTagClose t = (~== TagClose t)
+
+matchTagOpen :: Text -> [(Text, Text)] -> (Tag Text -> Bool)
+matchTagOpen t as = (~== TagOpen t as)
{-
@@ -1153,7 +1207,7 @@ types :: [(String, ([String], Int))]
types = -- Document divisions
map (\s -> (s, (["section", "body"], 0)))
["volume", "part", "chapter", "division"]
- ++ -- Document section and components
+ <> -- Document section and components
[
("abstract", ([], 0))]
-}
diff --git a/src/Text/Pandoc/Readers/Haddock.hs b/src/Text/Pandoc/Readers/Haddock.hs
index 28caa528e..b22b71b96 100644
--- a/src/Text/Pandoc/Readers/Haddock.hs
+++ b/src/Text/Pandoc/Readers/Haddock.hs
@@ -16,6 +16,7 @@ module Text.Pandoc.Readers.Haddock
import Control.Monad.Except (throwError)
import Data.List (intersperse, stripPrefix)
+import Data.Text (Text, unpack)
import Data.Maybe (fromMaybe)
import Data.Monoid ((<>))
import Documentation.Haddock.Parser
@@ -32,9 +33,9 @@ import Text.Pandoc.Shared (splitBy, trim)
-- | Parse Haddock markup and return a 'Pandoc' document.
readHaddock :: PandocMonad m
=> ReaderOptions
- -> String
+ -> Text
-> m Pandoc
-readHaddock opts s = case readHaddockEither opts s of
+readHaddock opts s = case readHaddockEither opts (unpack s) of
Right result -> return result
Left e -> throwError e
diff --git a/src/Text/Pandoc/Readers/LaTeX.hs b/src/Text/Pandoc/Readers/LaTeX.hs
index 1d13f7107..17fb48548 100644
--- a/src/Text/Pandoc/Readers/LaTeX.hs
+++ b/src/Text/Pandoc/Readers/LaTeX.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.LaTeX
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -39,6 +39,7 @@ import Control.Applicative (many, optional, (<|>))
import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (chr, isAlphaNum, isLetter, ord)
+import Data.Text (Text, unpack)
import Data.List (intercalate, isPrefixOf)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, maybeToList)
@@ -46,7 +47,7 @@ import Safe (minimumDef)
import System.FilePath (addExtension, replaceExtension, takeExtension)
import Text.Pandoc.Builder
import Text.Pandoc.Class (PandocMonad, PandocPure, lookupEnv, readFileFromDirs,
- report, setResourcePath)
+ report, setResourcePath, getResourcePath)
import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
import Text.Pandoc.ImageSize (numUnit, showFl)
import Text.Pandoc.Logging
@@ -59,10 +60,10 @@ import Text.Pandoc.Walk
-- | Parse LaTeX from string and return 'Pandoc' document.
readLaTeX :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assumes @'\n'@ line endings)
+ -> Text -- ^ String to parse (assumes @'\n'@ line endings)
-> m Pandoc
readLaTeX opts ltx = do
- parsed <- readWithM parseLaTeX def{ stateOptions = opts } ltx
+ parsed <- readWithM parseLaTeX def{ stateOptions = opts } (unpack ltx)
case parsed of
Right result -> return result
Left e -> throwError e
@@ -276,8 +277,6 @@ block = (mempty <$ comment)
<|> blockCommand
<|> paragraph
<|> grouped block
- <|> (mempty <$ char '&') -- loose & in table environment
-
blocks :: PandocMonad m => LP m Blocks
blocks = mconcat <$> many block
@@ -304,8 +303,8 @@ blockCommand = try $ do
rawcommand <- getRawCommand name'
transformed <- applyMacros' rawcommand
guard $ transformed /= rawcommand
- notFollowedBy $ parseFromString inlines transformed
- parseFromString blocks transformed
+ notFollowedBy $ parseFromString' inlines transformed
+ parseFromString' blocks transformed
lookupListDefault raw [name',name] blockCommands
inBrackets :: Inlines -> Inlines
@@ -432,7 +431,7 @@ coloredBlock stylename = do
graphicsPath :: PandocMonad m => LP m Blocks
graphicsPath = do
ps <- bgroup *> (manyTill braced egroup)
- setResourcePath (".":ps)
+ getResourcePath >>= setResourcePath . (++ ps)
return mempty
addMeta :: PandocMonad m => ToMetaValue a => String -> a -> LP m ()
@@ -490,16 +489,19 @@ inlineCommand = try $ do
transformed <- applyMacros' rawcommand
exts <- getOption readerExtensions
if transformed /= rawcommand
- then parseFromString inlines transformed
+ then parseFromString' inlines transformed
else if extensionEnabled Ext_raw_tex exts
then return $ rawInline "latex" rawcommand
else ignore rawcommand
(lookupListDefault raw [name',name] inlineCommands <*
optional (try (string "{}")))
-unlessParseRaw :: PandocMonad m => LP m ()
-unlessParseRaw = getOption readerExtensions >>=
- guard . not . extensionEnabled Ext_raw_tex
+rawInlineOr :: PandocMonad m => String -> LP m Inlines -> LP m Inlines
+rawInlineOr name' fallback = do
+ parseRaw <- extensionEnabled Ext_raw_tex <$> getOption readerExtensions
+ if parseRaw
+ then rawInline "latex" <$> getRawCommand name'
+ else fallback
isBlockCommand :: String -> Bool
isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Blocks))
@@ -507,20 +509,20 @@ isBlockCommand s = s `M.member` (blockCommands :: M.Map String (LP PandocPure Bl
inlineEnvironments :: PandocMonad m => M.Map String (LP m Inlines)
inlineEnvironments = M.fromList
- [ ("displaymath", mathEnv id Nothing "displaymath")
- , ("math", math <$> verbEnv "math")
- , ("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*")
+ [ ("displaymath", mathEnvWith id Nothing "displaymath")
+ , ("math", math <$> mathEnv "math")
+ , ("equation", mathEnvWith id Nothing "equation")
+ , ("equation*", mathEnvWith id Nothing "equation*")
+ , ("gather", mathEnvWith id (Just "gathered") "gather")
+ , ("gather*", mathEnvWith id (Just "gathered") "gather*")
+ , ("multline", mathEnvWith id (Just "gathered") "multline")
+ , ("multline*", mathEnvWith id (Just "gathered") "multline*")
+ , ("eqnarray", mathEnvWith id (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnvWith id (Just "aligned") "eqnarray*")
+ , ("align", mathEnvWith id (Just "aligned") "align")
+ , ("align*", mathEnvWith id (Just "aligned") "align*")
+ , ("alignat", mathEnvWith id (Just "aligned") "alignat")
+ , ("alignat*", mathEnvWith id (Just "aligned") "alignat*")
]
inlineCommands :: PandocMonad m => M.Map String (LP m Inlines)
@@ -547,11 +549,11 @@ inlineCommands = M.fromList $
, ("dots", lit "…")
, ("mdots", lit "…")
, ("sim", lit "~")
- , ("label", unlessParseRaw >> (inBrackets <$> tok))
- , ("ref", unlessParseRaw >> (inBrackets <$> tok))
+ , ("label", rawInlineOr "label" (inBrackets <$> tok))
+ , ("ref", rawInlineOr "ref" (inBrackets <$> tok))
, ("textgreek", tok)
, ("sep", lit ",")
- , ("cref", unlessParseRaw >> (inBrackets <$> tok)) -- from cleveref.sty
+ , ("cref", rawInlineOr "cref" (inBrackets <$> tok)) -- from cleveref.sty
, ("(", mathInline $ manyTill anyChar (try $ string "\\)"))
, ("[", mathDisplay $ manyTill anyChar (try $ string "\\]"))
, ("ensuremath", mathInline braced)
@@ -605,7 +607,7 @@ inlineCommands = M.fromList $
, ("u", option (str "u") $ try $ tok >>= accent breve)
, ("i", lit "i")
, ("\\", linebreak <$ (optional (bracketed inline) *> spaces'))
- , (",", pure mempty)
+ , (",", lit "\8198")
, ("@", pure mempty)
, (" ", lit "\160")
, ("ps", pure $ str "PS." <> space)
@@ -698,6 +700,9 @@ inlineCommands = M.fromList $
-- LaTeX colors
, ("textcolor", coloredInline "color")
, ("colorbox", coloredInline "background-color")
+ -- fontawesome
+ , ("faCheck", lit "\10003")
+ , ("faClose", lit "\10007")
] ++ map ignoreInlines
-- these commands will be ignored unless --parse-raw is specified,
-- in which case they will appear as raw latex blocks:
@@ -1045,7 +1050,7 @@ rawEnv name = do
(bs, raw) <- withRaw $ env name blocks
raw' <- applyMacros' $ beginCommand ++ raw
if raw' /= beginCommand ++ raw
- then parseFromString blocks raw'
+ then parseFromString' blocks raw'
else if parseRaw
then return $ rawBlock "latex" $ beginCommand ++ raw'
else do
@@ -1055,6 +1060,19 @@ rawEnv name = do
report $ SkippedContent ("\\end{" ++ name ++ "}") pos2
return bs
+rawVerbEnv :: PandocMonad m => String -> LP m Blocks
+rawVerbEnv name = do
+ pos <- getPosition
+ (_, raw) <- withRaw $ verbEnv name
+ let raw' = "\\begin{tikzpicture}" ++ raw
+ exts <- getOption readerExtensions
+ let parseRaw = extensionEnabled Ext_raw_tex exts
+ if parseRaw
+ then return $ rawBlock "latex" raw'
+ else do
+ report $ SkippedContent raw' pos
+ return mempty
+
----
maybeAddExtension :: String -> FilePath -> FilePath
@@ -1119,7 +1137,7 @@ parseListingsOptions options =
keyval :: PandocMonad m => LP m (String, String)
keyval = try $ do
key <- many1 alphaNum
- val <- option "" $ char '=' >> many1 (alphaNum <|> char '.' <|> char '\\')
+ val <- option "" $ char '=' >> braced <|> (many1 (alphaNum <|> oneOf ".:-|\\"))
skipMany spaceChar
optional (char ',')
skipMany spaceChar
@@ -1130,7 +1148,7 @@ keyvals :: PandocMonad m => LP m [(String, String)]
keyvals = try $ char '[' *> manyTill keyval (char ']')
alltt :: PandocMonad m => String -> LP m Blocks
-alltt t = walk strToCode <$> parseFromString blocks
+alltt t = walk strToCode <$> parseFromString' blocks
(substitute " " "\\ " $ substitute "%" "\\%" $
intercalate "\\\\\n" $ lines t)
where strToCode (Str s) = Code nullAttr s
@@ -1176,11 +1194,12 @@ environments = M.fromList
, ("subfigure", env "subfigure" $ skipopts *> tok *> figure)
, ("center", env "center" blocks)
, ("longtable", env "longtable" $
- resetCaption *> simpTable False >>= addTableCaption)
+ resetCaption *> simpTable "longtable" False >>= addTableCaption)
, ("table", env "table" $
resetCaption *> skipopts *> blocks >>= addTableCaption)
- , ("tabular*", env "tabular" $ simpTable True)
- , ("tabular", env "tabular" $ simpTable False)
+ , ("tabular*", env "tabular" $ simpTable "tabular*" True)
+ , ("tabularx", env "tabularx" $ simpTable "tabularx" True)
+ , ("tabular", env "tabular" $ simpTable "tabular" False)
, ("quote", blockQuote <$> env "quote" blocks)
, ("quotation", blockQuote <$> env "quotation" blocks)
, ("verse", blockQuote <$> env "verse" blocks)
@@ -1210,19 +1229,20 @@ environments = M.fromList
, ("obeylines", parseFromString
(para . trimInlines . mconcat <$> many inline) =<<
intercalate "\\\\\n" . lines <$> verbEnv "obeylines")
- , ("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*")
+ , ("displaymath", mathEnvWith para Nothing "displaymath")
+ , ("equation", mathEnvWith para Nothing "equation")
+ , ("equation*", mathEnvWith para Nothing "equation*")
+ , ("gather", mathEnvWith para (Just "gathered") "gather")
+ , ("gather*", mathEnvWith para (Just "gathered") "gather*")
+ , ("multline", mathEnvWith para (Just "gathered") "multline")
+ , ("multline*", mathEnvWith para (Just "gathered") "multline*")
+ , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
+ , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
+ , ("align", mathEnvWith para (Just "aligned") "align")
+ , ("align*", mathEnvWith para (Just "aligned") "align*")
+ , ("alignat", mathEnvWith para (Just "aligned") "alignat")
+ , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
+ , ("tikzpicture", rawVerbEnv "tikzpicture")
]
figure :: PandocMonad m => LP m Blocks
@@ -1287,19 +1307,32 @@ listenv name p = try $ do
updateState $ \st -> st{ stateParserContext = oldCtx }
return res
-mathEnv :: PandocMonad m => (Inlines -> a) -> Maybe String -> String -> LP m a
-mathEnv f innerEnv name = f <$> mathDisplay (inner <$> verbEnv name)
+mathEnvWith :: PandocMonad m
+ => (Inlines -> a) -> Maybe String -> String -> LP m a
+mathEnvWith f innerEnv name = f <$> mathDisplay (inner <$> mathEnv name)
where inner x = case innerEnv of
Nothing -> x
Just y -> "\\begin{" ++ y ++ "}\n" ++ x ++
"\\end{" ++ y ++ "}"
+mathEnv :: PandocMonad m => String -> LP m String
+mathEnv name = do
+ skipopts
+ optional blankline
+ let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
+ charMuncher = skipMany comment *>
+ (many1 (noneOf "\\%") <|> try (string "\\%")
+ <|> try (string "\\\\") <|> count 1 anyChar)
+ res <- concat <$> manyTill charMuncher endEnv
+ return $ stripTrailingNewlines res
+
verbEnv :: PandocMonad m => String -> LP m String
verbEnv name = do
skipopts
optional blankline
let endEnv = try $ controlSeq "end" *> braced >>= guard . (== name)
- res <- manyTill anyChar endEnv
+ charMuncher = anyChar
+ res <- manyTill charMuncher endEnv
return $ stripTrailingNewlines res
fancyverbEnv :: PandocMonad m => String -> LP m Blocks
@@ -1314,7 +1347,7 @@ fancyverbEnv name = do
codeBlockWith attr <$> verbEnv name
orderedList' :: PandocMonad m => LP m Blocks
-orderedList' = do
+orderedList' = try $ do
optional sp
(_, style, delim) <- option (1, DefaultStyle, DefaultDelim) $
try $ char '[' *> anyOrderedListMarker <* char ']'
@@ -1429,7 +1462,7 @@ complexNatbibCitation mode = try $ do
-- tables
-parseAligns :: PandocMonad m => LP m [(String, Alignment, String)]
+parseAligns :: PandocMonad m => LP m [(Alignment, Double, (String, String))]
parseAligns = try $ do
bgroup
let maybeBar = skipMany $ sp <|> () <$ char '|' <|> () <$ (char '@' >> braced)
@@ -1437,18 +1470,36 @@ parseAligns = try $ do
let cAlign = AlignCenter <$ char 'c'
let lAlign = AlignLeft <$ char 'l'
let rAlign = AlignRight <$ char 'r'
- let parAlign = AlignLeft <$ (char 'p' >> braced)
+ let parAlign = AlignLeft <$ char 'p'
+ -- algins from tabularx
+ let xAlign = AlignLeft <$ char 'X'
+ let mAlign = AlignLeft <$ char 'm'
+ let bAlign = AlignLeft <$ char 'b'
let alignChar = cAlign <|> lAlign <|> rAlign <|> parAlign
+ <|> xAlign <|> mAlign <|> bAlign
let alignPrefix = char '>' >> braced
let alignSuffix = char '<' >> braced
+ let colWidth = try $ do
+ char '{'
+ ds <- many1 (oneOf "0123456789.")
+ spaces
+ string "\\linewidth"
+ char '}'
+ case safeRead ds of
+ Just w -> return w
+ Nothing -> return 0.0
let alignSpec = do
spaces
pref <- option "" alignPrefix
spaces
- ch <- alignChar
+ al <- alignChar
+ width <- colWidth <|> option 0.0 (do s <- braced
+ pos <- getPosition
+ report $ SkippedContent s pos
+ return 0.0)
spaces
suff <- option "" alignSuffix
- return (pref, ch, suff)
+ return (al, width, (pref, suff))
aligns' <- sepEndBy alignSpec maybeBar
spaces
egroup
@@ -1478,24 +1529,26 @@ amp :: PandocMonad m => LP m ()
amp = () <$ try (spaces' *> char '&' <* spaces')
parseTableRow :: PandocMonad m
- => Int -- ^ number of columns
- -> [String] -- ^ prefixes
- -> [String] -- ^ suffixes
+ => String -- ^ table environment name
+ -> [(String, String)] -- ^ pref/suffixes
-> LP m [Blocks]
-parseTableRow cols prefixes suffixes = try $ do
- let tableCellRaw = many (notFollowedBy
- (amp <|> lbreak <|>
- (() <$ try (string "\\end"))) >> anyChar)
- let minipage = try $ controlSeq "begin" *> string "{minipage}" *>
- env "minipage"
- (skipopts *> spaces' *> optional braced *> spaces' *> blocks)
- let tableCell = minipage <|>
- ((plain . trimInlines . mconcat) <$> many inline)
+parseTableRow envname prefsufs = try $ do
+ let cols = length prefsufs
+ let tableCellRaw = concat <$> many
+ (do notFollowedBy amp
+ notFollowedBy lbreak
+ notFollowedBy $ () <$ try (string ("\\end{" ++ envname ++ "}"))
+ many1 (noneOf "&%\n\r\\")
+ <|> try (string "\\&")
+ <|> count 1 anyChar)
+ let plainify bs = case toList bs of
+ [Para ils] -> plain (fromList ils)
+ _ -> bs
rawcells <- sepBy1 tableCellRaw amp
guard $ length rawcells == cols
- let rawcells' = zipWith3 (\c p s -> p ++ trim c ++ s)
- rawcells prefixes suffixes
- cells' <- mapM (parseFromString tableCell) rawcells'
+ let rawcells' = zipWith (\c (p, s) -> p ++ trim c ++ s) rawcells prefsufs
+ let tableCell = plainify <$> blocks
+ cells' <- mapM (parseFromString' tableCell) rawcells'
let numcells = length cells'
guard $ numcells <= cols && numcells >= 1
guard $ cells' /= [mempty]
@@ -1507,21 +1560,22 @@ parseTableRow cols prefixes suffixes = try $ do
spaces' :: PandocMonad m => LP m ()
spaces' = spaces *> skipMany (comment *> spaces)
-simpTable :: PandocMonad m => Bool -> LP m Blocks
-simpTable hasWidthParameter = try $ do
+simpTable :: PandocMonad m => String -> Bool -> LP m Blocks
+simpTable envname hasWidthParameter = try $ do
when hasWidthParameter $ () <$ (spaces' >> tok)
skipopts
- (prefixes, aligns, suffixes) <- unzip3 <$> parseAligns
- let cols = length aligns
+ colspecs <- parseAligns
+ let (aligns, widths, prefsufs) = unzip3 colspecs
+ let cols = length colspecs
optional $ controlSeq "caption" *> skipopts *> setCaption
optional lbreak
spaces'
skipMany hline
spaces'
- header' <- option [] $ try (parseTableRow cols prefixes suffixes <*
+ header' <- option [] $ try (parseTableRow envname prefsufs <*
lbreak <* many1 hline)
spaces'
- rows <- sepEndBy (parseTableRow cols prefixes suffixes)
+ rows <- sepEndBy (parseTableRow envname prefsufs)
(lbreak <* optional (skipMany hline))
spaces'
optional $ controlSeq "caption" *> skipopts *> setCaption
@@ -1531,7 +1585,7 @@ simpTable hasWidthParameter = try $ do
then replicate cols mempty
else header'
lookAhead $ controlSeq "end" -- make sure we're at end
- return $ table mempty (zip aligns (repeat 0)) header'' rows
+ return $ table mempty (zip aligns widths) header'' rows
removeDoubleQuotes :: String -> String
removeDoubleQuotes ('"':xs) =
diff --git a/src/Text/Pandoc/Readers/Markdown.hs b/src/Text/Pandoc/Readers/Markdown.hs
index 5515c735b..e1c481311 100644
--- a/src/Text/Pandoc/Readers/Markdown.hs
+++ b/src/Text/Pandoc/Readers/Markdown.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Readers.Markdown
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -55,11 +55,9 @@ import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Emoji (emojis)
-import Text.Pandoc.Generic (bottomUp)
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (tableWith)
-import Text.Pandoc.Pretty (charWidth)
import Text.Pandoc.Readers.HTML (htmlInBalanced, htmlTag, isBlockTag,
isCommentTag, isInlineTag, isTextTag)
import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
@@ -72,10 +70,11 @@ type MarkdownParser m = ParserT [Char] ParserState m
-- | Read markdown from an input string and return a Pandoc document.
readMarkdown :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readMarkdown opts s = do
- parsed <- (readWithM parseMarkdown) def{ stateOptions = opts } (s ++ "\n\n")
+ parsed <- (readWithM parseMarkdown) def{ stateOptions = opts }
+ (T.unpack s ++ "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -155,9 +154,11 @@ litChar = escapedChar'
inlinesInBalancedBrackets :: PandocMonad m => MarkdownParser m (F Inlines)
inlinesInBalancedBrackets = do
char '['
+ pos <- getPosition
(_, raw) <- withRaw $ charsInBalancedBrackets 1
guard $ not $ null raw
- parseFromString (trimInlinesF . mconcat <$> many inline) (init raw)
+ parseFromString' (setPosition pos >>
+ trimInlinesF . mconcat <$> many inline) (init raw)
charsInBalancedBrackets :: PandocMonad m => Int -> MarkdownParser m ()
charsInBalancedBrackets 0 = return ()
@@ -189,7 +190,7 @@ rawTitleBlockLine = do
titleLine :: PandocMonad m => MarkdownParser m (F Inlines)
titleLine = try $ do
raw <- rawTitleBlockLine
- res <- parseFromString (many inline) raw
+ res <- parseFromString' (many inline) raw
return $ trimInlinesF $ mconcat res
authorsLine :: PandocMonad m => MarkdownParser m (F [Inlines])
@@ -200,12 +201,12 @@ authorsLine = try $ do
(trimInlinesF . mconcat <$> many
(try $ notFollowedBy sep >> inline))
sep
- sequence <$> parseFromString pAuthors raw
+ sequence <$> parseFromString' pAuthors raw
dateLine :: PandocMonad m => MarkdownParser m (F Inlines)
dateLine = try $ do
raw <- rawTitleBlockLine
- res <- parseFromString (many inline) raw
+ res <- parseFromString' (many inline) raw
return $ trimInlinesF $ mconcat res
titleBlock :: PandocMonad m => MarkdownParser m ()
@@ -290,7 +291,7 @@ ignorable t = (T.pack "_") `T.isSuffixOf` t
toMetaValue :: PandocMonad m
=> Text -> MarkdownParser m (F MetaValue)
-toMetaValue x = toMeta <$> parseFromString parseBlocks (T.unpack x)
+toMetaValue x = toMeta <$> parseFromString' parseBlocks (T.unpack x)
where
toMeta p = do
p' <- p
@@ -360,20 +361,20 @@ parseMarkdown = do
optional titleBlock
blocks <- parseBlocks
st <- getState
+ -- check for notes with no corresponding note references
+ let notesUsed = stateNoteRefs st
+ let notesDefined = M.keys (stateNotes' st)
+ mapM_ (\n -> unless (n `Set.member` notesUsed) $ do
+ -- lookup to get sourcepos
+ case M.lookup n (stateNotes' st) of
+ Just (pos, _) -> report (NoteDefinedButNotUsed n pos)
+ Nothing -> error "The impossible happened.") notesDefined
let doc = runF (do Pandoc _ bs <- B.doc <$> blocks
meta <- stateMeta' st
return $ Pandoc meta bs) st
reportLogMessages
(do guardEnabled Ext_east_asian_line_breaks
- return $ bottomUp softBreakFilter doc) <|> return doc
-
-softBreakFilter :: [Inline] -> [Inline]
-softBreakFilter (x:SoftBreak:y:zs) =
- case (stringify x, stringify y) of
- (xs@(_:_), (c:_))
- | charWidth (last xs) == 2 && charWidth c == 2 -> x:y:zs
- _ -> x:SoftBreak:y:zs
-softBreakFilter xs = xs
+ return $ eastAsianLineBreakFilter doc) <|> return doc
referenceKey :: PandocMonad m => MarkdownParser m (F Blocks)
referenceKey = try $ do
@@ -392,7 +393,9 @@ referenceKey = try $ do
src <- try betweenAngles <|> sourceURL
tit <- option "" referenceTitle
attr <- option nullAttr $ try $
- guardEnabled Ext_link_attributes >> skipSpaces >> attributes
+ do guardEnabled Ext_link_attributes
+ skipSpaces >> optional newline >> skipSpaces
+ attributes
addKvs <- option [] $ guardEnabled Ext_mmd_link_attributes
>> many (try $ spnl >> keyValAttr)
blanklines
@@ -402,8 +405,12 @@ referenceKey = try $ do
let oldkeys = stateKeys st
let key = toKey raw
case M.lookup key oldkeys of
- Just _ -> logMessage $ DuplicateLinkReference raw pos
- Nothing -> return ()
+ Just (t,a) | not (t == target && a == attr') ->
+ -- We don't warn on two duplicate keys if the targets are also
+ -- the same. This can happen naturally with --reference-location=block
+ -- or section. See #3701.
+ logMessage $ DuplicateLinkReference raw pos
+ _ -> return ()
updateState $ \s -> s { stateKeys = M.insert key (target, attr') oldkeys }
return $ return mempty
@@ -464,13 +471,12 @@ noteBlock = try $ do
rest <- many $ try $ blanklines >> indentSpaces >> rawLines
let raw = unlines (first:rest) ++ "\n"
optional blanklines
- parsed <- parseFromString parseBlocks raw
- let newnote = (ref, parsed)
+ parsed <- parseFromString' parseBlocks raw
oldnotes <- stateNotes' <$> getState
- case lookup ref oldnotes of
+ case M.lookup ref oldnotes of
Just _ -> logMessage $ DuplicateNoteReference ref pos
Nothing -> return ()
- updateState $ \s -> s { stateNotes' = newnote : oldnotes }
+ updateState $ \s -> s { stateNotes' = M.insert ref (pos, parsed) oldnotes }
return mempty
--
@@ -614,7 +620,7 @@ hrule = try $ do
--
indentedLine :: PandocMonad m => MarkdownParser m String
-indentedLine = indentSpaces >> anyLine >>= return . (++ "\n")
+indentedLine = indentSpaces >> anyLineNewline
blockDelimiter :: PandocMonad m
=> (Char -> Bool)
@@ -772,7 +778,7 @@ blockQuote :: PandocMonad m => MarkdownParser m (F Blocks)
blockQuote = do
raw <- emailBlockQuote
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ (intercalate "\n" raw) ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ (intercalate "\n" raw) ++ "\n\n"
return $ B.blockQuote <$> contents
--
@@ -868,8 +874,7 @@ listContinuationLine = try $ do
notFollowedBy' listStart
notFollowedByHtmlCloser
optional indentSpaces
- result <- anyLine
- return $ result ++ "\n"
+ anyLineNewline
listItem :: PandocMonad m
=> MarkdownParser m a
@@ -885,7 +890,7 @@ listItem start = try $ do
setState $ state {stateParserContext = ListItemState}
-- parse the extracted block, which may contain various block elements:
let raw = concat (first:continuations)
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
updateState (\st -> st {stateParserContext = oldContext})
return contents
@@ -932,8 +937,8 @@ definitionListItem :: PandocMonad m => Bool -> MarkdownParser m (F (Inlines, [Bl
definitionListItem compact = try $ do
rawLine' <- anyLine
raw <- many1 $ defRawBlock compact
- term <- parseFromString (trimInlinesF . mconcat <$> many inline) rawLine'
- contents <- mapM (parseFromString parseBlocks . (++"\n")) raw
+ term <- parseFromString' (trimInlinesF . mconcat <$> many inline) rawLine'
+ contents <- mapM (parseFromString' parseBlocks . (++"\n")) raw
optional blanklines
return $ liftM2 (,) term (sequence contents)
@@ -941,7 +946,7 @@ defRawBlock :: PandocMonad m => Bool -> MarkdownParser m String
defRawBlock compact = try $ do
hasBlank <- option False $ blankline >> return True
defListMarker
- firstline <- anyLine
+ firstline <- anyLineNewline
let dline = try
( do notFollowedBy blankline
notFollowedByHtmlCloser
@@ -956,7 +961,7 @@ defRawBlock compact = try $ do
ln <- indentSpaces >> notFollowedBy blankline >> anyLine
lns <- many dline
return $ trailing ++ unlines (ln:lns)
- return $ trimr (firstline ++ "\n" ++ unlines rawlines ++ cont) ++
+ return $ trimr (firstline ++ unlines rawlines ++ cont) ++
if hasBlank || not (null cont) then "\n\n" else ""
definitionList :: PandocMonad m => MarkdownParser m (F Blocks)
@@ -1088,13 +1093,19 @@ rawTeXBlock = do
rawHtmlBlocks :: PandocMonad m => MarkdownParser m (F Blocks)
rawHtmlBlocks = do
(TagOpen tagtype _, raw) <- htmlTag isBlockTag
+ -- we don't want '<td> text' to be a code block:
+ skipMany spaceChar
+ indentlevel <- (blankline >> length <$> many (char ' ')) <|> return 0
-- try to find closing tag
-- we set stateInHtmlBlock so that closing tags that can be either block or
-- inline will not be parsed as inline tags
oldInHtmlBlock <- stateInHtmlBlock <$> getState
updateState $ \st -> st{ stateInHtmlBlock = Just tagtype }
let closer = htmlTag (\x -> x ~== TagClose tagtype)
- contents <- mconcat <$> many (notFollowedBy' closer >> block)
+ let block' = do notFollowedBy' closer
+ atMostSpaces indentlevel
+ block
+ contents <- mconcat <$> many block'
result <-
(closer >>= \(_, rawcloser) -> return (
return (B.rawBlock "html" $ stripMarkdownAttribute raw) <>
@@ -1119,7 +1130,7 @@ lineBlock :: PandocMonad m => MarkdownParser m (F Blocks)
lineBlock = try $ do
guardEnabled Ext_line_blocks
lines' <- lineBlockLines >>=
- mapM (parseFromString (trimInlinesF . mconcat <$> many inline))
+ mapM (parseFromString' (trimInlinesF . mconcat <$> many inline))
return $ B.lineBlock <$> sequence lines'
--
@@ -1162,7 +1173,7 @@ simpleTableHeader headless = try $ do
then replicate (length dashes) ""
else rawHeads
heads <- fmap sequence
- $ mapM (parseFromString (mconcat <$> many plain))
+ $ mapM (parseFromString' (mconcat <$> many plain))
$ map trim rawHeads'
return (heads, aligns, indices)
@@ -1208,7 +1219,7 @@ tableLine :: PandocMonad m
=> [Int]
-> MarkdownParser m (F [Blocks])
tableLine indices = rawTableLine indices >>=
- fmap sequence . mapM (parseFromString (mconcat <$> many plain))
+ fmap sequence . mapM (parseFromString' (mconcat <$> many plain))
-- Parse a multiline table row and return a list of blocks (columns).
multilineRow :: PandocMonad m
@@ -1217,7 +1228,7 @@ multilineRow :: PandocMonad m
multilineRow indices = do
colLines <- many1 (rawTableLine indices)
let cols = map unlines $ transpose colLines
- fmap sequence $ mapM (parseFromString (mconcat <$> many plain)) cols
+ fmap sequence $ mapM (parseFromString' (mconcat <$> many plain)) cols
-- Parses a table caption: inlines beginning with 'Table:'
-- and followed by blank lines.
@@ -1275,7 +1286,7 @@ multilineTableHeader headless = try $ do
then replicate (length dashes) ""
else map (unlines . map trim) rawHeadsList
heads <- fmap sequence $
- mapM (parseFromString (mconcat <$> many plain)) $
+ mapM (parseFromString' (mconcat <$> many plain)) $
map trim rawHeads
return (heads, aligns, indices)
@@ -1285,89 +1296,7 @@ multilineTableHeader headless = try $ do
-- ending with a footer (dashed line followed by blank line).
gridTable :: PandocMonad m => Bool -- ^ Headerless table
-> MarkdownParser m ([Alignment], [Double], F [Blocks], F [[Blocks]])
-gridTable headless =
- tableWith (gridTableHeader headless) gridTableRow
- (gridTableSep '-') gridTableFooter
-
-gridTableSplitLine :: [Int] -> String -> [String]
-gridTableSplitLine indices line = map removeFinalBar $ tail $
- splitStringByIndices (init indices) $ trimr line
-
-gridPart :: PandocMonad m => Char -> ParserT [Char] st m ((Int, Int), Alignment)
-gridPart ch = do
- leftColon <- option False (True <$ char ':')
- dashes <- many1 (char ch)
- rightColon <- option False (True <$ char ':')
- char '+'
- let lengthDashes = length dashes + (if leftColon then 1 else 0) +
- (if rightColon then 1 else 0)
- let alignment = case (leftColon, rightColon) of
- (True, True) -> AlignCenter
- (True, False) -> AlignLeft
- (False, True) -> AlignRight
- (False, False) -> AlignDefault
- return ((lengthDashes, lengthDashes + 1), alignment)
-
-gridDashedLines :: PandocMonad m => Char -> ParserT [Char] st m [((Int, Int), Alignment)]
-gridDashedLines ch = try $ char '+' >> many1 (gridPart ch) <* blankline
-
-removeFinalBar :: String -> String
-removeFinalBar =
- reverse . dropWhile (`elem` " \t") . dropWhile (=='|') . reverse
-
--- | Separator between rows of grid table.
-gridTableSep :: PandocMonad m => Char -> MarkdownParser m Char
-gridTableSep ch = try $ gridDashedLines ch >> return '\n'
-
--- | Parse header for a grid table.
-gridTableHeader :: PandocMonad m => Bool -- ^ Headerless table
- -> MarkdownParser m (F [Blocks], [Alignment], [Int])
-gridTableHeader headless = try $ do
- optional blanklines
- dashes <- gridDashedLines '-'
- rawContent <- if headless
- then return []
- else many1 (try (char '|' >> anyLine))
- underDashes <- if headless
- then return dashes
- else gridDashedLines '='
- guard $ length dashes == length underDashes
- let lines' = map (snd . fst) underDashes
- let indices = scanl (+) 0 lines'
- let aligns = map snd underDashes
- let rawHeads = if headless
- then replicate (length underDashes) ""
- else map (unlines . map trim) $ transpose
- $ map (gridTableSplitLine indices) rawContent
- heads <- fmap sequence $ mapM (parseFromString parseBlocks . trim) rawHeads
- return (heads, aligns, indices)
-
-gridTableRawLine :: PandocMonad m => [Int] -> MarkdownParser m [String]
-gridTableRawLine indices = do
- char '|'
- line <- anyLine
- return (gridTableSplitLine indices line)
-
--- | Parse row of grid table.
-gridTableRow :: PandocMonad m => [Int]
- -> MarkdownParser m (F [Blocks])
-gridTableRow indices = do
- colLines <- many1 (gridTableRawLine indices)
- let cols = map ((++ "\n") . unlines . removeOneLeadingSpace) $
- transpose colLines
- fmap compactify <$> fmap sequence (mapM (parseFromString parseBlocks) cols)
-
-removeOneLeadingSpace :: [String] -> [String]
-removeOneLeadingSpace xs =
- if all startsWithSpace xs
- then map (drop 1) xs
- else xs
- where startsWithSpace "" = True
- startsWithSpace (y:_) = y == ' '
-
--- | Parse footer for a grid table.
-gridTableFooter :: PandocMonad m => MarkdownParser m [Char]
-gridTableFooter = blanklines
+gridTable headless = gridTableWith' parseBlocks headless
pipeBreak :: PandocMonad m => MarkdownParser m ([Alignment], [Int])
pipeBreak = try $ do
@@ -1414,7 +1343,7 @@ pipeTableRow = try $ do
let chunk = void (code <|> math <|> rawHtmlInline <|> escapedChar <|> rawLaTeXInline')
<|> void (noneOf "|\n\r")
let cellContents = ((trim . snd) <$> withRaw (many chunk)) >>=
- parseFromString pipeTableCell
+ parseFromString' pipeTableCell
cells <- cellContents `sepEndBy1` (char '|')
-- surrounding pipes needed for a one-column table:
guard $ not (length cells == 1 && not openPipe)
@@ -1522,6 +1451,7 @@ inline = choice [ whitespace
, autoLink
, spanHtml
, rawHtmlInline
+ , escapedNewline
, escapedChar
, rawLaTeXInline'
, exampleRef
@@ -1538,16 +1468,20 @@ escapedChar' = try $ do
(guardEnabled Ext_all_symbols_escapable >> satisfy (not . isAlphaNum))
<|> (guardEnabled Ext_angle_brackets_escapable >>
oneOf "\\`*_{}[]()>#+-.!~\"<>")
- <|> (guardEnabled Ext_escaped_line_breaks >> char '\n')
<|> oneOf "\\`*_{}[]()>#+-.!~\""
+escapedNewline :: PandocMonad m => MarkdownParser m (F Inlines)
+escapedNewline = try $ do
+ guardEnabled Ext_escaped_line_breaks
+ char '\\'
+ lookAhead (char '\n') -- don't consume the newline (see #3730)
+ return $ return B.linebreak
+
escapedChar :: PandocMonad m => MarkdownParser m (F Inlines)
escapedChar = do
result <- escapedChar'
case result of
' ' -> return $ return $ B.str "\160" -- "\ " is a nonbreaking space
- '\n' -> guardEnabled Ext_escaped_line_breaks >>
- return (return B.linebreak) -- "\[newline]" is a linebreak
_ -> return $ return $ B.str [result]
ltSign :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1629,9 +1563,9 @@ ender c n = try $ do
three :: PandocMonad m => Char -> MarkdownParser m (F Inlines)
three c = do
contents <- mconcat <$> many (notFollowedBy (ender c 1) >> inline)
- (ender c 3 >> return ((B.strong . B.emph) <$> contents))
- <|> (ender c 2 >> one c (B.strong <$> contents))
- <|> (ender c 1 >> two c (B.emph <$> contents))
+ (ender c 3 >> updateLastStrPos >> return ((B.strong . B.emph) <$> contents))
+ <|> (ender c 2 >> updateLastStrPos >> one c (B.strong <$> contents))
+ <|> (ender c 1 >> updateLastStrPos >> two c (B.emph <$> contents))
<|> return (return (B.str [c,c,c]) <> contents)
-- Parse inlines til you hit two c's, and emit strong.
@@ -1639,7 +1573,8 @@ three c = do
two :: PandocMonad m => Char -> F Inlines -> MarkdownParser m (F Inlines)
two c prefix' = do
contents <- mconcat <$> many (try $ notFollowedBy (ender c 2) >> inline)
- (ender c 2 >> return (B.strong <$> (prefix' <> contents)))
+ (ender c 2 >> updateLastStrPos >>
+ return (B.strong <$> (prefix' <> contents)))
<|> return (return (B.str [c,c]) <> (prefix' <> contents))
-- Parse inlines til you hit a c, and emit emph.
@@ -1650,7 +1585,7 @@ one c prefix' = do
<|> try (string [c,c] >>
notFollowedBy (ender c 1) >>
two c mempty) )
- (ender c 1 >> return (B.emph <$> (prefix' <> contents)))
+ (ender c 1 >> updateLastStrPos >> return (B.emph <$> (prefix' <> contents)))
<|> return (return (B.str [c]) <> (prefix' <> contents))
strongOrEmph :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -1814,15 +1749,17 @@ referenceLink :: PandocMonad m
referenceLink constructor (lab, raw) = do
sp <- (True <$ lookAhead (char ' ')) <|> return False
(_,raw') <- option (mempty, "") $
- lookAhead (try (guardEnabled Ext_citations >>
- spnl >> normalCite >> return (mempty, "")))
+ lookAhead (try (do guardEnabled Ext_citations
+ guardDisabled Ext_spaced_reference_links <|> spnl
+ normalCite
+ return (mempty, "")))
<|>
- try (spnl >> reference)
+ try ((guardDisabled Ext_spaced_reference_links <|> 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'
- fallback <- parseFromString (mconcat <$> many inline) $ dropBrackets raw
+ parsedRaw <- parseFromString' (mconcat <$> many inline) raw'
+ fallback <- parseFromString' (mconcat <$> many inline) $ dropBrackets raw
implicitHeaderRefs <- option False $
True <$ guardEnabled Ext_implicit_header_references
let makeFallback = do
@@ -1887,16 +1824,17 @@ note :: PandocMonad m => MarkdownParser m (F Inlines)
note = try $ do
guardEnabled Ext_footnotes
ref <- noteMarker
+ updateState $ \st -> st{ stateNoteRefs = Set.insert ref (stateNoteRefs st) }
return $ do
notes <- asksF stateNotes'
- case lookup ref notes of
+ case M.lookup ref notes of
Nothing -> return $ B.str $ "[^" ++ ref ++ "]"
- Just contents -> do
+ Just (_pos, contents) -> do
st <- askF
-- process the note in a context that doesn't resolve
-- notes, to avoid infinite looping with notes inside
-- notes:
- let contents' = runF contents st{ stateNotes' = [] }
+ let contents' = runF contents st{ stateNotes' = M.empty }
return $ B.note contents'
inlineNote :: PandocMonad m => MarkdownParser m (F Inlines)
@@ -2028,7 +1966,7 @@ textualCite = try $ do
let (spaces',raw') = span isSpace raw
spc | null spaces' = mempty
| otherwise = B.space
- lab <- parseFromString (mconcat <$> many inline) $ dropBrackets raw'
+ lab <- parseFromString' (mconcat <$> many inline) $ dropBrackets raw'
fallback <- referenceLink B.linkWith (lab,raw')
return $ do
fallback' <- fallback
diff --git a/src/Text/Pandoc/Readers/MediaWiki.hs b/src/Text/Pandoc/Readers/MediaWiki.hs
index b35f39aad..a3ff60c14 100644
--- a/src/Text/Pandoc/Readers/MediaWiki.hs
+++ b/src/Text/Pandoc/Readers/MediaWiki.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE TypeSynonymInstances #-}
-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
{-
- Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+ Copyright (C) 2012-2017 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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.MediaWiki
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -41,6 +41,7 @@ module Text.Pandoc.Readers.MediaWiki ( readMediaWiki ) where
import Control.Monad
import Control.Monad.Except (throwError)
import Data.Char (isDigit, isSpace)
+import Data.Text (Text, unpack)
import qualified Data.Foldable as F
import Data.List (intercalate, intersperse, isPrefixOf)
import qualified Data.Map as M
@@ -64,7 +65,7 @@ import Text.Pandoc.XML (fromEntities)
-- | Read mediawiki from an input string and return a Pandoc document.
readMediaWiki :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readMediaWiki opts s = do
parsed <- readWithM parseMediaWiki MWState{ mwOptions = opts
@@ -74,8 +75,9 @@ readMediaWiki opts s = do
, mwHeaderMap = M.empty
, mwIdentifierList = Set.empty
, mwLogMessages = []
+ , mwInTT = False
}
- (s ++ "\n")
+ (unpack s ++ "\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -87,6 +89,7 @@ data MWState = MWState { mwOptions :: ReaderOptions
, mwHeaderMap :: M.Map Inlines String
, mwIdentifierList :: Set.Set String
, mwLogMessages :: [LogMessage]
+ , mwInTT :: Bool
}
type MWParser m = ParserT [Char] MWState m
@@ -569,7 +572,12 @@ inlineTag = do
TagOpen "sub" _ -> B.subscript <$> inlinesInTags "sub"
TagOpen "sup" _ -> B.superscript <$> inlinesInTags "sup"
TagOpen "code" _ -> encode <$> inlinesInTags "code"
- TagOpen "tt" _ -> encode <$> inlinesInTags "tt"
+ TagOpen "tt" _ -> do
+ inTT <- mwInTT <$> getState
+ updateState $ \st -> st{ mwInTT = True }
+ result <- encode <$> inlinesInTags "tt"
+ updateState $ \st -> st{ mwInTT = inTT }
+ return result
TagOpen "hask" _ -> B.codeWith ("",["haskell"],[]) <$> charsInTags "hask"
_ -> B.rawInline "html" . snd <$> htmlTag (~== tag)
@@ -688,6 +696,10 @@ strong = B.strong <$> nested (inlinesBetween start end)
end = try $ sym "'''"
doubleQuotes :: PandocMonad m => MWParser m Inlines
-doubleQuotes = B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
+doubleQuotes = do
+ guardEnabled Ext_smart
+ inTT <- mwInTT <$> getState
+ guard (not inTT)
+ B.doubleQuoted <$> nested (inlinesBetween openDoubleQuote closeDoubleQuote)
where openDoubleQuote = sym "\"" >> lookAhead nonspaceChar
closeDoubleQuote = try $ sym "\""
diff --git a/src/Text/Pandoc/Readers/Native.hs b/src/Text/Pandoc/Readers/Native.hs
index 2e307fa4f..abc2ed38a 100644
--- a/src/Text/Pandoc/Readers/Native.hs
+++ b/src/Text/Pandoc/Readers/Native.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2011-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2017 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.Native
- Copyright : Copyright (C) 2011-2015 John MacFarlane
+ Copyright : Copyright (C) 2011-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -37,6 +37,7 @@ import Text.Pandoc.Shared (safeRead)
import Control.Monad.Except (throwError)
import Text.Pandoc.Class
import Text.Pandoc.Error
+import Data.Text (Text, unpack)
-- | Read native formatted text and return a Pandoc document.
-- The input may be a full pandoc document, a block list, a block,
@@ -50,22 +51,22 @@ import Text.Pandoc.Error
--
readNative :: PandocMonad m
=> ReaderOptions
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readNative _ s =
- case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead s) of
+ case maybe (Pandoc nullMeta <$> readBlocks s) Right (safeRead (unpack s)) of
Right doc -> return doc
Left _ -> throwError $ PandocParseError "couldn't read native"
-readBlocks :: String -> Either PandocError [Block]
-readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead s)
+readBlocks :: Text -> Either PandocError [Block]
+readBlocks s = maybe ((:[]) <$> readBlock s) Right (safeRead (unpack s))
-readBlock :: String -> Either PandocError Block
-readBlock s = maybe (Plain <$> readInlines s) Right (safeRead s)
+readBlock :: Text -> Either PandocError Block
+readBlock s = maybe (Plain <$> readInlines s) Right (safeRead (unpack s))
-readInlines :: String -> Either PandocError [Inline]
-readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead s)
+readInlines :: Text -> Either PandocError [Inline]
+readInlines s = maybe ((:[]) <$> readInline s) Right (safeRead (unpack s))
-readInline :: String -> Either PandocError Inline
-readInline s = maybe (Left . PandocParseError $ "Could not read: " ++ s) Right (safeRead s)
+readInline :: Text -> Either PandocError Inline
+readInline s = maybe (Left . PandocParseError $ "Could not read: " ++ unpack s) Right (safeRead (unpack s))
diff --git a/src/Text/Pandoc/Readers/OPML.hs b/src/Text/Pandoc/Readers/OPML.hs
index cf1c8f479..591d7590e 100644
--- a/src/Text/Pandoc/Readers/OPML.hs
+++ b/src/Text/Pandoc/Readers/OPML.hs
@@ -2,6 +2,7 @@
module Text.Pandoc.Readers.OPML ( readOPML ) where
import Control.Monad.State
import Data.Char (toUpper)
+import Data.Text (Text, unpack, pack)
import Data.Default
import Data.Generics
import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -28,9 +29,10 @@ instance Default OPMLState where
, opmlDocDate = mempty
}
-readOPML :: PandocMonad m => ReaderOptions -> String -> m Pandoc
+readOPML :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
readOPML _ inp = do
- (bs, st') <- flip runStateT def (mapM parseBlock $ normalizeTree $ parseXML inp)
+ (bs, st') <- flip runStateT def
+ (mapM parseBlock $ normalizeTree $ parseXML (unpack inp))
return $
setTitle (opmlDocTitle st') $
setAuthors (opmlDocAuthors st') $
@@ -69,10 +71,10 @@ asHtml :: PandocMonad m => String -> OPML m Inlines
asHtml s =
(\(Pandoc _ bs) -> case bs of
[Plain ils] -> fromList ils
- _ -> mempty) <$> (lift $ readHtml def s)
+ _ -> mempty) <$> (lift $ readHtml def (pack s))
asMarkdown :: PandocMonad m => String -> OPML m Blocks
-asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> (lift $ readMarkdown def s)
+asMarkdown s = (\(Pandoc _ bs) -> fromList bs) <$> (lift $ readMarkdown def (pack s))
getBlocks :: PandocMonad m => Element -> OPML m Blocks
getBlocks e = mconcat <$> (mapM parseBlock $ elContent e)
diff --git a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
index b056f1ecc..3d716ba19 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/State.hs
@@ -59,10 +59,6 @@ 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
@@ -79,10 +75,6 @@ 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)
@@ -107,43 +99,9 @@ instance ArrowChoice (ArrowState state) where
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.
@@ -175,42 +133,6 @@ 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)
@@ -239,15 +161,3 @@ iterateS' a = ArrowState $ \(s,f) -> foldr (a' s) (s,Right mzero) f
(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
index 218a85661..ecef8b6e3 100644
--- a/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs
@@ -40,10 +40,7 @@ with an equivalent return value.
module Text.Pandoc.Readers.Odt.Arrows.Utils where
import Control.Arrow
-import Control.Monad ( join, MonadPlus(..) )
-
-import qualified Data.Foldable as F
-import Data.Monoid
+import Control.Monad ( join )
import Text.Pandoc.Readers.Odt.Generic.Fallible
import Text.Pandoc.Readers.Odt.Generic.Utils
@@ -63,12 +60,6 @@ and5 :: (Arrow a)
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 )
@@ -78,10 +69,6 @@ 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
@@ -98,19 +85,11 @@ liftA5 :: (Arrow a) => (z->y->x->w->v -> 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
@@ -124,28 +103,12 @@ liftA fun a = a >>^ fun
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.)
(>>%) :: (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 >>%, %<<, %>>, <<%
+infixr 2 >>%
-- | Duplicate a value and apply an arrow to the second instance.
@@ -156,56 +119,6 @@ infixr 2 >>%, %<<, %>>, <<%
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
@@ -218,33 +131,12 @@ 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')
+infixr 3 ^&&&, &&&^
-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)
@@ -258,130 +150,15 @@ maybeToChoice = arr maybeToEither
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)
=> FallibleArrow a x failure success
@@ -410,20 +187,6 @@ a >>?^? b = a >>> Left ^|||^ b
-> FallibleArrow a x failure success'
a ^>>? b = a ^>> Left ^||| b
--- | Execute the lifted second arrow if the lifted first arrow succeeds
-(^>>?^) :: (ArrowChoice a)
- => (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)
- => (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)
=> FallibleArrow a x failure success
@@ -453,33 +216,9 @@ a ^>>?% f = arr a >>?^ (uncurry f)
a >>?%? f = a >>?^? (uncurry f)
infixr 1 >>?, >>?^, >>?^?
-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
@@ -489,7 +228,4 @@ 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/ContentReader.hs b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
index a1bd8cb59..777c10df5 100644
--- a/src/Text/Pandoc/Readers/Odt/ContentReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/ContentReader.hs
@@ -94,8 +94,6 @@ data ReaderState
, envMedia :: Media
-- | Hold binary resources used in the document
, odtMediaBag :: MediaBag
--- , sequences
--- , trackedChangeIDs
}
deriving ( Show )
@@ -899,9 +897,6 @@ read_reference_ref = matchingElement NsText "reference-ref"
-- 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
diff --git a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
index 877443543..4d6a67b8e 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs
@@ -39,10 +39,6 @@ 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.
@@ -51,16 +47,6 @@ 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
@@ -71,21 +57,11 @@ 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
@@ -110,24 +86,6 @@ 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.
@@ -152,87 +110,11 @@ chooseMaxWith _ _ (Right b) = Right b
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] }
@@ -247,14 +129,3 @@ instance ChoiceVector SuccessList where
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/Utils.hs b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
index 6c10ed61d..4af4242b6 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/Utils.hs
@@ -38,8 +38,6 @@ module Text.Pandoc.Readers.Odt.Generic.Utils
, uncurry4
, uncurry5
, uncurry6
-, uncurry7
-, uncurry8
, swap
, reverseComposition
, bool
@@ -148,15 +146,11 @@ 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)
@@ -168,4 +162,3 @@ 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
index 8c03d1a09..1c3e08a7f 100644
--- a/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
+++ b/src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs
@@ -41,50 +41,17 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, 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
@@ -93,25 +60,9 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
, readAttr'
, readAttrWithDefault
, getAttr
--- , (>/<)
--- , (?>/<)
, executeIn
-, collectEvery
, withEveryL
-, withEvery
, tryAll
-, tryAll'
-, IdXMLConverter
-, MaybeEConverter
-, ElementMatchConverter
-, MaybeCConverter
-, ContentMatchConverter
-, makeMatcherE
-, makeMatcherC
-, prepareMatchersE
-, prepareMatchersC
-, matchChildren
-, matchContent''
, matchContent'
, matchContent
) where
@@ -121,7 +72,6 @@ import Control.Monad ( MonadPlus )
import Control.Arrow
import qualified Data.Map as M
-import qualified Data.Foldable as F
import Data.Default
import Data.Maybe
@@ -210,17 +160,6 @@ 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] )
@@ -264,14 +203,6 @@ runConverter :: XMLConverter nsID extraState input output
-> 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
@@ -280,20 +211,6 @@ runConverter' :: (NameSpaceID nsID)
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
@@ -430,57 +347,15 @@ elemNameIs nsID name = keepingTheValue (lookupNSiri nsID) >>% hasThatName
--------------------------------------------------------------------------------
--
-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
@@ -490,18 +365,6 @@ findChildren nsID name = elemName nsID name
>>% 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
@@ -517,45 +380,12 @@ findChild :: (NameSpaceID nsID)
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)
@@ -570,34 +400,6 @@ 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)
@@ -608,18 +410,6 @@ 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)
@@ -789,16 +579,6 @@ 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
@@ -826,16 +606,6 @@ 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
--------------------------------------------------------------------------------
@@ -843,15 +613,6 @@ tryAll' nsID name a = prepareIteration nsID name
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))
@@ -862,26 +623,6 @@ type ContentMatchConverter nsID extraState x
(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
@@ -914,13 +655,6 @@ makeMatcherC nsID name c = ( second ( contentToElem
_ -> 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
@@ -928,52 +662,6 @@ prepareMatchersC :: (NameSpaceID nsID)
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)
@@ -1018,14 +706,6 @@ matchContent lookups 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
diff --git a/src/Text/Pandoc/Readers/Odt/StyleReader.hs b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
index 26ba6df82..87a6dc91c 100644
--- a/src/Text/Pandoc/Readers/Odt/StyleReader.hs
+++ b/src/Text/Pandoc/Readers/Odt/StyleReader.hs
@@ -50,23 +50,11 @@ module Text.Pandoc.Readers.Odt.StyleReader
, ListLevelType (..)
, LengthOrPercent (..)
, lookupStyle
-, getTextProperty
-, getTextProperty'
-, getParaProperty
-, getListStyle
, getListLevelStyle
, getStyleFamily
-, lookupDefaultStyle
, lookupDefaultStyle'
, lookupListStyleByName
-, getPropertyChain
-, textPropertyChain
-, stylePropertyChain
-, stylePropertyChain'
-, getStylePropertyChain
, extendedStylePropertyChain
-, extendedStylePropertyChain'
-, liftStyles
, readStylesAt
) where
@@ -83,7 +71,6 @@ 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
@@ -624,20 +611,11 @@ 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
@@ -681,64 +659,3 @@ extendedStylePropertyChain [style] styles = (stylePropertyChain style s
++ (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 5e509178d..5e0d67d10 100644
--- a/src/Text/Pandoc/Readers/Org.hs
+++ b/src/Text/Pandoc/Readers/Org.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -18,7 +18,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Org
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -40,15 +40,18 @@ import Text.Pandoc.Parsing (reportLogMessages)
import Control.Monad.Except (throwError)
import Control.Monad.Reader (runReaderT)
+import Data.Text (Text)
+import qualified Data.Text as T
-- | Parse org-mode string and return a Pandoc document.
readOrg :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readOrg opts s = do
parsed <- flip runReaderT def $
- readWithM parseOrg (optionsToParserState opts) (s ++ "\n\n")
+ readWithM parseOrg (optionsToParserState opts)
+ (T.unpack s ++ "\n\n")
case parsed of
Right result -> return result
Left _ -> throwError $ PandocParseError "problem parsing org"
diff --git a/src/Text/Pandoc/Readers/Org/BlockStarts.hs b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
index cc2e82d5b..9c6614c99 100644
--- a/src/Text/Pandoc/Readers/Org/BlockStarts.hs
+++ b/src/Text/Pandoc/Readers/Org/BlockStarts.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.BlockStarts
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -61,8 +61,12 @@ headerStart = try $
tableStart :: Monad m => OrgParser m Char
tableStart = try $ skipSpaces *> char '|'
+gridTableStart :: Monad m => OrgParser m ()
+gridTableStart = try $ skipSpaces <* char '+' <* char '-'
+
+
latexEnvStart :: Monad m => OrgParser m String
-latexEnvStart = try $ do
+latexEnvStart = try $
skipSpaces *> string "\\begin{"
*> latexEnvName
<* string "}"
@@ -93,8 +97,7 @@ orderedListStart = genericListStart orderedListMarker
where orderedListMarker = mappend <$> many1 digit <*> (pure <$> oneOf ".)")
drawerStart :: Monad m => OrgParser m String
-drawerStart = try $
- skipSpaces *> drawerName <* skipSpaces <* newline
+drawerStart = try $ skipSpaces *> drawerName <* skipSpaces <* newline
where drawerName = char ':' *> manyTill nonspaceChar (char ':')
metaLineStart :: Monad m => OrgParser m ()
@@ -116,8 +119,8 @@ noteMarker = try $ do
-- | Succeeds if the parser is at the end of a block.
endOfBlock :: Monad m => OrgParser m ()
-endOfBlock = lookAhead . try $ do
- void blankline <|> anyBlockStart
+endOfBlock = lookAhead . try $
+ void blankline <|> anyBlockStart
where
-- Succeeds if there is a new block starting at this position.
anyBlockStart :: Monad m => OrgParser m ()
@@ -126,6 +129,7 @@ endOfBlock = lookAhead . try $ do
, hline
, metaLineStart
, commentLineStart
+ , gridTableStart
, void noteMarker
, void tableStart
, void drawerStart
@@ -134,4 +138,3 @@ endOfBlock = lookAhead . try $ do
, void bulletListStart
, void orderedListStart
]
-
diff --git a/src/Text/Pandoc/Readers/Org/Blocks.hs b/src/Text/Pandoc/Readers/Org/Blocks.hs
index b0a19b833..3e0ab0127 100644
--- a/src/Text/Pandoc/Readers/Org/Blocks.hs
+++ b/src/Text/Pandoc/Readers/Org/Blocks.hs
@@ -1,6 +1,3 @@
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE RecordWildCards #-}
-{-# LANGUAGE ViewPatterns #-}
{-
Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -18,9 +15,10 @@ 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
-}
-
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
+ Module : Text.Pandoc.Readers.Org.Blocks
Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
@@ -34,6 +32,7 @@ module Text.Pandoc.Readers.Org.Blocks
) where
import Text.Pandoc.Readers.Org.BlockStarts
+import Text.Pandoc.Readers.Org.DocumentTree (documentTree, headlineToBlocks)
import Text.Pandoc.Readers.Org.Inlines
import Text.Pandoc.Readers.Org.Meta (metaExport, metaKey, metaLine)
import Text.Pandoc.Readers.Org.ParserState
@@ -52,211 +51,21 @@ import Control.Monad (foldM, guard, mzero, void)
import Data.Char (isSpace, toLower, toUpper)
import Data.Default (Default)
import Data.List (foldl', isPrefixOf)
-import Data.Maybe (fromMaybe, isNothing)
+import Data.Maybe (fromMaybe, isJust, isNothing)
import Data.Monoid ((<>))
--
--- Org headers
---
-newtype Tag = Tag { fromTag :: String }
- deriving (Show, Eq)
-
--- | Create a tag containing the given string.
-toTag :: String -> Tag
-toTag = Tag
-
--- | The key (also called name or type) of a property.
-newtype PropertyKey = PropertyKey { fromKey :: String }
- deriving (Show, Eq, Ord)
-
--- | Create a property key containing the given string. Org mode keys are
--- case insensitive and are hence converted to lower case.
-toPropertyKey :: String -> PropertyKey
-toPropertyKey = PropertyKey . map toLower
-
--- | The value assigned to a property.
-newtype PropertyValue = PropertyValue { fromValue :: String }
-
--- | Create a property value containing the given string.
-toPropertyValue :: String -> PropertyValue
-toPropertyValue = PropertyValue
-
--- | Check whether the property value is non-nil (i.e. truish).
-isNonNil :: PropertyValue -> Bool
-isNonNil p = map toLower (fromValue p) `notElem` ["()", "{}", "nil"]
-
--- | Key/value pairs from a PROPERTIES drawer
-type Properties = [(PropertyKey, PropertyValue)]
-
--- | Org mode headline (i.e. a document subtree).
-data Headline = Headline
- { headlineLevel :: Int
- , headlineTodoMarker :: Maybe TodoMarker
- , headlineText :: Inlines
- , headlineTags :: [Tag]
- , headlineProperties :: Properties
- , headlineContents :: Blocks
- , headlineChildren :: [Headline]
- }
-
---
--- Parsing headlines and subtrees
---
-
--- | Read an Org mode headline and its contents (i.e. a document subtree).
--- @lvl@ gives the minimum acceptable level of the tree.
-headline :: PandocMonad m => Int -> OrgParser m (F Headline)
-headline lvl = try $ do
- level <- headerStart
- guard (lvl <= level)
- todoKw <- optionMaybe todoKeyword
- title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
- tags <- option [] headerTags
- newline
- properties <- option mempty propertiesDrawer
- contents <- blocks
- children <- many (headline (level + 1))
- return $ do
- title' <- title
- contents' <- contents
- children' <- sequence children
- return $ Headline
- { headlineLevel = level
- , headlineTodoMarker = todoKw
- , headlineText = title'
- , headlineTags = tags
- , headlineProperties = properties
- , headlineContents = contents'
- , headlineChildren = children'
- }
- where
- endOfTitle :: Monad m => OrgParser m ()
- endOfTitle = void . lookAhead $ optional headerTags *> newline
-
- headerTags :: Monad m => OrgParser m [Tag]
- headerTags = try $
- let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
- in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
-
--- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
-headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
-headlineToBlocks hdln@(Headline {..}) = do
- maxHeadlineLevels <- getExportSetting exportHeadlineLevels
- case () of
- _ | any isNoExportTag headlineTags -> return mempty
- _ | any isArchiveTag headlineTags -> archivedHeadlineToBlocks hdln
- _ | isCommentTitle headlineText -> return mempty
- _ | headlineLevel >= maxHeadlineLevels -> headlineToHeaderWithList hdln
- _ | otherwise -> headlineToHeaderWithContents hdln
-
-isNoExportTag :: Tag -> Bool
-isNoExportTag = (== toTag "noexport")
-
-isArchiveTag :: Tag -> Bool
-isArchiveTag = (== toTag "ARCHIVE")
-
--- | Check if the title starts with COMMENT.
--- FIXME: This accesses builder internals not intended for use in situations
--- like these. Replace once keyword parsing is supported.
-isCommentTitle :: Inlines -> Bool
-isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
-isCommentTitle _ = False
-
-archivedHeadlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
-archivedHeadlineToBlocks hdln = do
- archivedTreesOption <- getExportSetting exportArchivedTrees
- case archivedTreesOption of
- ArchivedTreesNoExport -> return mempty
- ArchivedTreesExport -> headlineToHeaderWithContents hdln
- ArchivedTreesHeadlineOnly -> headlineToHeader hdln
-
-headlineToHeaderWithList :: Monad m => Headline -> OrgParser m Blocks
-headlineToHeaderWithList hdln@(Headline {..}) = do
- maxHeadlineLevels <- getExportSetting exportHeadlineLevels
- header <- headlineToHeader hdln
- listElements <- sequence (map headlineToBlocks headlineChildren)
- let listBlock = if null listElements
- then mempty
- else B.orderedList listElements
- let headerText = if maxHeadlineLevels == headlineLevel
- then header
- else flattenHeader header
- return $ headerText <> headlineContents <> listBlock
- where
- flattenHeader :: Blocks -> Blocks
- flattenHeader blks =
- case B.toList blks of
- (Header _ _ inlns:_) -> B.para (B.fromList inlns)
- _ -> mempty
-
-headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks
-headlineToHeaderWithContents hdln@(Headline {..}) = do
- header <- headlineToHeader hdln
- childrenBlocks <- mconcat <$> sequence (map headlineToBlocks headlineChildren)
- return $ header <> headlineContents <> childrenBlocks
-
-headlineToHeader :: Monad m => Headline -> OrgParser m Blocks
-headlineToHeader (Headline {..}) = do
- exportTodoKeyword <- getExportSetting exportWithTodoKeywords
- let todoText = if exportTodoKeyword
- then case headlineTodoMarker of
- Just kw -> todoKeywordToInlines kw <> B.space
- Nothing -> mempty
- else mempty
- let text = tagTitle (todoText <> headlineText) headlineTags
- let propAttr = propertiesToAttr headlineProperties
- attr <- registerHeader propAttr headlineText
- return $ B.headerWith attr headlineLevel text
-
-todoKeyword :: Monad m => OrgParser m TodoMarker
-todoKeyword = try $ do
- taskStates <- activeTodoMarkers <$> getState
- let kwParser tdm = try $ (tdm <$ string (todoMarkerName tdm) <* spaceChar)
- choice (map kwParser taskStates)
-
-todoKeywordToInlines :: TodoMarker -> Inlines
-todoKeywordToInlines tdm =
- let todoText = todoMarkerName tdm
- todoState = map toLower . show $ todoMarkerState tdm
- classes = [todoState, todoText]
- in B.spanWith (mempty, classes, mempty) (B.str todoText)
-
-propertiesToAttr :: Properties -> Attr
-propertiesToAttr properties =
- let
- toStringPair prop = (fromKey (fst prop), fromValue (snd prop))
- customIdKey = toPropertyKey "custom_id"
- classKey = toPropertyKey "class"
- unnumberedKey = toPropertyKey "unnumbered"
- specialProperties = [customIdKey, classKey, unnumberedKey]
- id' = fromMaybe mempty . fmap fromValue . lookup customIdKey $ properties
- cls = fromMaybe mempty . fmap fromValue . lookup classKey $ properties
- kvs' = map toStringPair . filter ((`notElem` specialProperties) . fst)
- $ properties
- isUnnumbered =
- fromMaybe False . fmap isNonNil . lookup unnumberedKey $ properties
- in
- (id', words cls ++ (if isUnnumbered then ["unnumbered"] else []), kvs')
-
-tagTitle :: Inlines -> [Tag] -> Inlines
-tagTitle title tags = title <> (mconcat $ map tagToInline tags)
-
-tagToInline :: Tag -> Inlines
-tagToInline t = B.spanWith ("", ["tag"], [("data-tag-name", fromTag t)]) mempty
-
-
---
-- parsing blocks
--
-- | Get a list of blocks.
blockList :: PandocMonad m => OrgParser m [Block]
blockList = do
- initialBlocks <- blocks
- headlines <- sequence <$> manyTill (headline 1) eof
+ headlines <- documentTree blocks inline
st <- getState
- headlineBlocks <- fmap mconcat . sequence . map headlineToBlocks $ runF headlines st
- return . B.toList $ (runF initialBlocks st) <> headlineBlocks
+ headlineBlocks <- headlineToBlocks $ runF headlines st
+ -- ignore first headline, it's the document's title
+ return . drop 1 . B.toList $ headlineBlocks
-- | Get the meta information saved in the state.
meta :: Monad m => OrgParser m Meta
@@ -274,6 +83,7 @@ block = choice [ mempty <$ blanklines
, figure
, example
, genericDrawer
+ , include
, specialLine
, horizontalRule
, list
@@ -302,7 +112,7 @@ data BlockAttributes = BlockAttributes
-- | Convert BlockAttributes into pandoc Attr
attrFromBlockAttributes :: BlockAttributes -> Attr
-attrFromBlockAttributes (BlockAttributes{..}) =
+attrFromBlockAttributes BlockAttributes{..} =
let
ident = fromMaybe mempty $ lookup "id" blockAttrKeyValues
classes = case lookup "class" blockAttrKeyValues of
@@ -311,18 +121,18 @@ attrFromBlockAttributes (BlockAttributes{..}) =
kv = filter ((`notElem` ["id", "class"]) . fst) blockAttrKeyValues
in (ident, classes, kv)
-stringyMetaAttribute :: Monad m => (String -> Bool) -> OrgParser m (String, String)
-stringyMetaAttribute attrCheck = try $ do
+stringyMetaAttribute :: Monad m => OrgParser m (String, String)
+stringyMetaAttribute = try $ do
metaLineStart
attrName <- map toUpper <$> many1Till nonspaceChar (char ':')
- guard $ attrCheck attrName
skipSpaces
- attrValue <- anyLine
+ attrValue <- anyLine <|> ("" <$ newline)
return (attrName, attrValue)
blockAttributes :: PandocMonad m => OrgParser m BlockAttributes
blockAttributes = try $ do
- kv <- many (stringyMetaAttribute attrCheck)
+ kv <- many stringyMetaAttribute
+ guard $ all (attrCheck . fst) kv
let caption = foldl' (appendValues "CAPTION") Nothing kv
let kvAttrs = foldl' (appendValues "ATTR_HTML") Nothing kv
let name = lookup "NAME" kv
@@ -331,7 +141,7 @@ blockAttributes = try $ do
Nothing -> return Nothing
Just s -> Just <$> parseFromString inlines (s ++ "\n")
kvAttrs' <- parseFromString keyValues . (++ "\n") $ fromMaybe mempty kvAttrs
- return $ BlockAttributes
+ return BlockAttributes
{ blockAttrName = name
, blockAttrLabel = label
, blockAttrCaption = caption'
@@ -339,13 +149,7 @@ blockAttributes = try $ do
}
where
attrCheck :: String -> Bool
- attrCheck attr =
- case attr of
- "NAME" -> True
- "LABEL" -> True
- "CAPTION" -> True
- "ATTR_HTML" -> True
- _ -> False
+ attrCheck x = x `elem` ["NAME", "LABEL", "CAPTION", "ATTR_HTML", "RESULTS"]
appendValues :: String -> Maybe String -> (String, String) -> Maybe String
appendValues attrName accValue (key, value) =
@@ -355,6 +159,7 @@ blockAttributes = try $ do
Just acc -> Just $ acc ++ ' ':value
Nothing -> Just value
+-- | Parse key-value pairs for HTML attributes
keyValues :: Monad m => OrgParser m [(String, String)]
keyValues = try $
manyTill ((,) <$> key <*> value) newline
@@ -381,7 +186,7 @@ orgBlock = try $ do
blockAttrs <- blockAttributes
blkType <- blockHeaderStart
($ blkType) $
- case (map toLower blkType) of
+ case map toLower blkType of
"export" -> exportBlock
"comment" -> rawBlockLines (const mempty)
"html" -> rawBlockLines (return . B.rawBlock (lowercase blkType))
@@ -402,10 +207,10 @@ orgBlock = try $ do
lowercase = map toLower
rawBlockLines :: Monad m => (String -> F Blocks) -> String -> OrgParser m (F Blocks)
-rawBlockLines f blockType = (ignHeaders *> (f <$> rawBlockContent blockType))
+rawBlockLines f blockType = ignHeaders *> (f <$> rawBlockContent blockType)
parseBlockLines :: PandocMonad m => (F Blocks -> F Blocks) -> String -> OrgParser m (F Blocks)
-parseBlockLines f blockType = (ignHeaders *> (f <$> parsedBlockContent))
+parseBlockLines f blockType = ignHeaders *> (f <$> parsedBlockContent)
where
parsedBlockContent :: PandocMonad m => OrgParser m (F Blocks)
parsedBlockContent = try $ do
@@ -433,8 +238,7 @@ rawBlockContent blockType = try $ do
stripIndent strs = map (drop (shortestIndent strs)) strs
shortestIndent :: [String] -> Int
- shortestIndent = foldr min maxBound
- . map (length . takeWhile isSpace)
+ shortestIndent = foldr (min . length . takeWhile isSpace) maxBound
. filter (not . null)
tabsToSpaces :: Int -> String -> String
@@ -442,7 +246,7 @@ rawBlockContent blockType = try $ do
tabsToSpaces tabLen cs'@(c:cs) =
case c of
' ' -> ' ':tabsToSpaces tabLen cs
- '\t' -> (take tabLen $ repeat ' ') ++ tabsToSpaces tabLen cs
+ '\t' -> replicate tabLen ' ' ++ tabsToSpaces tabLen cs
_ -> cs'
commaEscaped :: String -> String
@@ -490,16 +294,15 @@ codeBlock blockAttrs blockType = do
skipSpaces
(classes, kv) <- codeHeaderArgs <|> (mempty <$ ignHeaders)
content <- rawBlockContent blockType
- resultsContent <- trailingResultsBlock
+ resultsContent <- option mempty babelResultsBlock
let id' = fromMaybe mempty $ blockAttrName blockAttrs
let codeBlck = B.codeBlockWith ( id', classes, kv ) content
let labelledBlck = maybe (pure codeBlck)
(labelDiv codeBlck)
(blockAttrCaption blockAttrs)
- let resultBlck = fromMaybe mempty resultsContent
return $
- (if exportsCode kv then labelledBlck else mempty) <>
- (if exportsResults kv then resultBlck else mempty)
+ (if exportsCode kv then labelledBlck else mempty) <>
+ (if exportsResults kv then resultsContent else mempty)
where
labelDiv :: Blocks -> F Inlines -> F Blocks
labelDiv blk value =
@@ -514,12 +317,16 @@ codeBlock blockAttrs blockType = do
exportsResults :: [(String, String)] -> Bool
exportsResults = maybe False (`elem` ["results", "both"]) . lookup "exports"
-trailingResultsBlock :: PandocMonad m => OrgParser m (Maybe (F Blocks))
-trailingResultsBlock = optionMaybe . try $ do
+-- | Parse the result of an evaluated babel code block.
+babelResultsBlock :: PandocMonad m => OrgParser m (F Blocks)
+babelResultsBlock = try $ do
blanklines
- stringAnyCase "#+RESULTS:"
- blankline
+ resultsMarker <|>
+ (lookAhead . void . try $
+ manyTill (metaLineStart *> anyLineNewline) resultsMarker)
block
+ where
+ resultsMarker = try . void $ stringAnyCase "#+RESULTS:" *> blankline
-- | Parse code block arguments
codeHeaderArgs :: Monad m => OrgParser m ([String], [(String, String)])
@@ -527,13 +334,13 @@ codeHeaderArgs = try $ do
language <- skipSpaces *> orgArgWord
(switchClasses, switchKv) <- switchesAsAttributes
parameters <- manyTill blockOption newline
- return $ ( translateLang language : switchClasses
- , originalLang language <> switchKv <> parameters
- )
+ return ( translateLang language : switchClasses
+ , originalLang language <> switchKv <> parameters
+ )
switchesAsAttributes :: Monad m => OrgParser m ([String], [(String, String)])
switchesAsAttributes = try $ do
- switches <- skipSpaces *> (try $ switch `sepBy` (many1 spaceChar))
+ switches <- skipSpaces *> try (switch `sepBy` many1 spaceChar)
return $ foldr addToAttr ([], []) switches
where
addToAttr :: (Char, Maybe String, SwitchPolarity)
@@ -541,10 +348,10 @@ switchesAsAttributes = try $ do
-> ([String], [(String, String)])
addToAttr ('n', lineNum, pol) (cls, kv) =
let kv' = case lineNum of
- Just num -> (("startFrom", num):kv)
+ Just num -> ("startFrom", num):kv
Nothing -> kv
cls' = case pol of
- SwitchPlus -> "continuedSourceBlock":cls
+ SwitchPlus -> "continuedSourceBlock":cls
SwitchMinus -> cls
in ("numberLines":cls', kv')
addToAttr _ x = x
@@ -573,7 +380,7 @@ genericSwitch :: Monad m
genericSwitch c p = try $ do
polarity <- switchPolarity <* char c <* skipSpaces
arg <- optionMaybe p
- return $ (c, arg, polarity)
+ return (c, arg, polarity)
-- | Reads a line number switch option. The line number switch can be used with
-- example and source blocks.
@@ -593,8 +400,8 @@ orgParamValue = try $
*> noneOf "\n\r" `many1Till` endOfValue
<* skipSpaces
where
- endOfValue = lookAhead $ (try $ skipSpaces <* oneOf "\n\r")
- <|> (try $ skipSpaces1 <* orgArgKey)
+ endOfValue = lookAhead $ try (skipSpaces <* oneOf "\n\r")
+ <|> try (skipSpaces1 <* orgArgKey)
--
@@ -612,7 +419,7 @@ genericDrawer = try $ do
-- Include drawer if it is explicitly included in or not explicitly excluded
-- from the list of drawers that should be exported. PROPERTIES drawers are
-- never exported.
- case (exportDrawers . orgStateExportSettings $ state) of
+ case exportDrawers . orgStateExportSettings $ state of
_ | name == "PROPERTIES" -> return mempty
Left names | name `elem` names -> return mempty
Right names | name `notElem` names -> return mempty
@@ -631,25 +438,6 @@ drawerEnd :: Monad m => OrgParser m String
drawerEnd = try $
skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
--- | Read a :PROPERTIES: drawer and return the key/value pairs contained
--- within.
-propertiesDrawer :: Monad m => OrgParser m Properties
-propertiesDrawer = try $ do
- drawerType <- drawerStart
- guard $ map toUpper drawerType == "PROPERTIES"
- manyTill property (try drawerEnd)
- where
- property :: Monad m => OrgParser m (PropertyKey, PropertyValue)
- property = try $ (,) <$> key <*> value
-
- key :: Monad m => OrgParser m PropertyKey
- key = fmap toPropertyKey . try $
- skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
-
- value :: Monad m => OrgParser m PropertyValue
- value = fmap toPropertyValue . try $
- skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
-
--
-- Figures
@@ -665,7 +453,7 @@ figure = try $ do
Nothing -> mzero
Just imgSrc -> do
guard (isImageFilename imgSrc)
- let isFigure = not . isNothing $ blockAttrCaption figAttrs
+ let isFigure = isJust $ blockAttrCaption figAttrs
return $ imageBlock isFigure figAttrs imgSrc
where
selfTarget :: PandocMonad m => OrgParser m String
@@ -700,8 +488,7 @@ endOfParagraph = try $ skipSpaces *> newline *> endOfBlock
-- | Example code marked up by a leading colon.
example :: Monad m => OrgParser m (F Blocks)
-example = try $ do
- returnF . exampleCode =<< unlines <$> many1 exampleLine
+example = try $ returnF . exampleCode =<< unlines <$> many1 exampleLine
where
exampleLine :: Monad m => OrgParser m String
exampleLine = try $ exampleLineStart *> anyLine
@@ -717,6 +504,34 @@ exampleCode = B.codeBlockWith ("", ["example"], [])
specialLine :: PandocMonad m => OrgParser m (F Blocks)
specialLine = fmap return . try $ rawExportLine <|> metaLine <|> commentLine
+-- | Include the content of a file.
+include :: PandocMonad m => OrgParser m (F Blocks)
+include = try $ do
+ metaLineStart <* stringAnyCase "include:" <* skipSpaces
+ filename <- includeTarget
+ blockType <- optionMaybe $ skipSpaces *> many1 alphaNum
+ blocksParser <- case blockType of
+ Just "example" ->
+ return $ pure . B.codeBlock <$> parseRaw
+ Just "export" -> do
+ format <- skipSpaces *> many (noneOf "\n\r\t ")
+ return $ pure . B.rawBlock format <$> parseRaw
+ Just "src" -> do
+ language <- skipSpaces *> many (noneOf "\n\r\t ")
+ let attr = (mempty, [language], mempty)
+ return $ pure . B.codeBlockWith attr <$> parseRaw
+ _ -> return $ pure . B.fromList <$> blockList
+ anyLine
+ insertIncludedFileF blocksParser ["."] filename
+ where
+ includeTarget :: PandocMonad m => OrgParser m FilePath
+ includeTarget = do
+ char '"'
+ manyTill (noneOf "\n\r\t") (char '"')
+
+ parseRaw :: PandocMonad m => OrgParser m String
+ parseRaw = many anyChar
+
rawExportLine :: PandocMonad m => OrgParser m Blocks
rawExportLine = try $ do
metaLineStart
@@ -755,11 +570,15 @@ data OrgTable = OrgTable
}
table :: PandocMonad m => OrgParser m (F Blocks)
-table = try $ do
+table = gridTableWith blocks True <|> orgTable
+
+-- | A normal org table
+orgTable :: PandocMonad m => OrgParser m (F Blocks)
+orgTable = try $ do
-- don't allow a table on the first line of a list item; org requires that
-- tables start at first non-space character on the line
- let isFirstInListItem st = (orgStateParserContext st == ListItemState) &&
- (orgStateLastPreCharPos st == Nothing)
+ let isFirstInListItem st = orgStateParserContext st == ListItemState &&
+ isNothing (orgStateLastPreCharPos st)
guard =<< not . isFirstInListItem <$> getState
blockAttrs <- blockAttributes
lookAhead tableStart
@@ -772,7 +591,7 @@ orgToPandocTable :: OrgTable
-> Inlines
-> Blocks
orgToPandocTable (OrgTable colProps heads lns) caption =
- let totalWidth = if any (not . isNothing) (map columnRelWidth colProps)
+ let totalWidth = if any isJust (map columnRelWidth colProps)
then Just . sum $ map (fromMaybe 1 . columnRelWidth) colProps
else Nothing
in B.table caption (map (convertColProp totalWidth) colProps) heads lns
@@ -782,7 +601,7 @@ orgToPandocTable (OrgTable colProps heads lns) caption =
let
align' = fromMaybe AlignDefault $ columnAlignment colProp
width' = fromMaybe 0 $ (\w t -> (fromIntegral w / fromIntegral t))
- <$> (columnRelWidth colProp)
+ <$> columnRelWidth colProp
<*> totalWidth
in (align', width')
@@ -808,7 +627,7 @@ tableAlignRow = try $ do
columnPropertyCell :: Monad m => OrgParser m ColumnProperty
columnPropertyCell = emptyCell <|> propCell <?> "alignment info"
where
- emptyCell = ColumnProperty Nothing Nothing <$ (try $ skipSpaces *> endOfCell)
+ emptyCell = ColumnProperty Nothing Nothing <$ try (skipSpaces *> endOfCell)
propCell = try $ ColumnProperty
<$> (skipSpaces
*> char '<'
@@ -854,28 +673,28 @@ normalizeTable (OrgTable colProps heads rows) =
rowToContent :: OrgTable
-> OrgTableRow
-> F OrgTable
-rowToContent orgTable row =
+rowToContent tbl row =
case row of
OrgHlineRow -> return singleRowPromotedToHeader
OrgAlignRow props -> return . setProperties $ props
OrgContentRow cs -> appendToBody cs
where
singleRowPromotedToHeader :: OrgTable
- singleRowPromotedToHeader = case orgTable of
- OrgTable{ orgTableHeader = [], orgTableRows = b:[] } ->
- orgTable{ orgTableHeader = b , orgTableRows = [] }
- _ -> orgTable
+ singleRowPromotedToHeader = case tbl of
+ OrgTable{ orgTableHeader = [], orgTableRows = [b] } ->
+ tbl{ orgTableHeader = b , orgTableRows = [] }
+ _ -> tbl
setProperties :: [ColumnProperty] -> OrgTable
- setProperties ps = orgTable{ orgTableColumnProperties = ps }
+ setProperties ps = tbl{ orgTableColumnProperties = ps }
appendToBody :: F [Blocks] -> F OrgTable
appendToBody frow = do
newRow <- frow
- let oldRows = orgTableRows orgTable
+ let oldRows = orgTableRows tbl
-- NOTE: This is an inefficient O(n) operation. This should be changed
-- if performance ever becomes a problem.
- return orgTable{ orgTableRows = oldRows ++ [newRow] }
+ return tbl{ orgTableRows = oldRows ++ [newRow] }
--
@@ -917,7 +736,7 @@ noteBlock = try $ do
paraOrPlain :: PandocMonad m => OrgParser m (F Blocks)
paraOrPlain = try $ do
-- Make sure we are not looking at a headline
- notFollowedBy' (char '*' *> (oneOf " *"))
+ notFollowedBy' (char '*' *> oneOf " *")
ils <- inlines
nl <- option False (newline *> return True)
-- Read block as paragraph, except if we are in a list context and the block
@@ -926,7 +745,7 @@ paraOrPlain = try $ do
try (guard nl
*> notFollowedBy (inList *> (() <$ orderedListStart <|> bulletListStart))
*> return (B.para <$> ils))
- <|> (return (B.plain <$> ils))
+ <|> return (B.plain <$> ils)
--
@@ -938,16 +757,16 @@ list = choice [ definitionList, bulletList, orderedList ] <?> "list"
definitionList :: PandocMonad m => OrgParser m (F Blocks)
definitionList = try $ do n <- lookAhead (bulletListStart' Nothing)
- fmap B.definitionList . fmap compactifyDL . sequence
+ fmap (B.definitionList . compactifyDL) . sequence
<$> many1 (definitionListItem $ bulletListStart' (Just n))
bulletList :: PandocMonad m => OrgParser m (F Blocks)
bulletList = try $ do n <- lookAhead (bulletListStart' Nothing)
- fmap B.bulletList . fmap compactify . sequence
+ fmap (B.bulletList . compactify) . sequence
<$> many1 (listItem (bulletListStart' $ Just n))
orderedList :: PandocMonad m => OrgParser m (F Blocks)
-orderedList = fmap B.orderedList . fmap compactify . sequence
+orderedList = fmap (B.orderedList . compactify) . sequence
<$> many1 (listItem orderedListStart)
bulletListStart' :: Monad m => Maybe Int -> OrgParser m Int
@@ -1004,16 +823,3 @@ listContinuation markerLength = try $
<*> many blankline)
where
listLine = try $ indentWith markerLength *> anyLineNewline
-
- -- indent by specified number of spaces (or equiv. tabs)
- indentWith :: Monad m => Int -> OrgParser m String
- indentWith num = do
- tabStop <- getOption readerTabStop
- if num < tabStop
- then count num (char ' ')
- else choice [ try (count num (char ' '))
- , try (char '\t' >> count (num - tabStop) (char ' ')) ]
-
--- | Parse any line, include the final newline in the output.
-anyLineNewline :: Monad m => OrgParser m String
-anyLineNewline = (++ "\n") <$> anyLine
diff --git a/src/Text/Pandoc/Readers/Org/DocumentTree.hs b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
new file mode 100644
index 000000000..743f6cc0e
--- /dev/null
+++ b/src/Text/Pandoc/Readers/Org/DocumentTree.hs
@@ -0,0 +1,304 @@
+{-
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
+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
+-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE ViewPatterns #-}
+{- |
+ Module : Text.Pandoc.Readers.Org.DocumentTree
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
+ License : GNU GPL, version 2 or above
+
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+
+Parsers for org-mode headlines and document subtrees
+-}
+module Text.Pandoc.Readers.Org.DocumentTree
+ ( documentTree
+ , headlineToBlocks
+ ) where
+
+import Control.Arrow ((***))
+import Control.Monad (guard, void)
+import Data.Char (toLower, toUpper)
+import Data.List (intersperse)
+import Data.Monoid ((<>))
+import Text.Pandoc.Builder (Blocks, Inlines)
+import Text.Pandoc.Class (PandocMonad)
+import Text.Pandoc.Definition
+import Text.Pandoc.Readers.Org.BlockStarts
+import Text.Pandoc.Readers.Org.ParserState
+import Text.Pandoc.Readers.Org.Parsing
+
+import qualified Data.Map as Map
+import qualified Text.Pandoc.Builder as B
+
+--
+-- Org headers
+--
+
+-- | Parse input as org document tree.
+documentTree :: PandocMonad m
+ => OrgParser m (F Blocks)
+ -> OrgParser m (F Inlines)
+ -> OrgParser m (F Headline)
+documentTree blocks inline = do
+ initialBlocks <- blocks
+ headlines <- sequence <$> manyTill (headline blocks inline 1) eof
+ title <- fmap (getTitle . unMeta) . orgStateMeta <$> getState
+ return $ do
+ headlines' <- headlines
+ initialBlocks' <- initialBlocks
+ title' <- title
+ return Headline
+ { headlineLevel = 0
+ , headlineTodoMarker = Nothing
+ , headlineText = B.fromList title'
+ , headlineTags = mempty
+ , headlineProperties = mempty
+ , headlineContents = initialBlocks'
+ , headlineChildren = headlines'
+ }
+ where
+ getTitle :: Map.Map String MetaValue -> [Inline]
+ getTitle metamap =
+ case Map.lookup "title" metamap of
+ Just (MetaInlines inlns) -> inlns
+ _ -> []
+
+newtype Tag = Tag { fromTag :: String }
+ deriving (Show, Eq)
+
+-- | Create a tag containing the given string.
+toTag :: String -> Tag
+toTag = Tag
+
+-- | The key (also called name or type) of a property.
+newtype PropertyKey = PropertyKey { fromKey :: String }
+ deriving (Show, Eq, Ord)
+
+-- | Create a property key containing the given string. Org mode keys are
+-- case insensitive and are hence converted to lower case.
+toPropertyKey :: String -> PropertyKey
+toPropertyKey = PropertyKey . map toLower
+
+-- | The value assigned to a property.
+newtype PropertyValue = PropertyValue { fromValue :: String }
+
+-- | Create a property value containing the given string.
+toPropertyValue :: String -> PropertyValue
+toPropertyValue = PropertyValue
+
+-- | Check whether the property value is non-nil (i.e. truish).
+isNonNil :: PropertyValue -> Bool
+isNonNil p = map toLower (fromValue p) `notElem` ["()", "{}", "nil"]
+
+-- | Key/value pairs from a PROPERTIES drawer
+type Properties = [(PropertyKey, PropertyValue)]
+
+-- | Org mode headline (i.e. a document subtree).
+data Headline = Headline
+ { headlineLevel :: Int
+ , headlineTodoMarker :: Maybe TodoMarker
+ , headlineText :: Inlines
+ , headlineTags :: [Tag]
+ , headlineProperties :: Properties
+ , headlineContents :: Blocks
+ , headlineChildren :: [Headline]
+ }
+
+-- | Read an Org mode headline and its contents (i.e. a document subtree).
+-- @lvl@ gives the minimum acceptable level of the tree.
+headline :: PandocMonad m
+ => OrgParser m (F Blocks)
+ -> OrgParser m (F Inlines)
+ -> Int
+ -> OrgParser m (F Headline)
+headline blocks inline lvl = try $ do
+ level <- headerStart
+ guard (lvl <= level)
+ todoKw <- optionMaybe todoKeyword
+ title <- trimInlinesF . mconcat <$> manyTill inline endOfTitle
+ tags <- option [] headerTags
+ newline
+ properties <- option mempty propertiesDrawer
+ contents <- blocks
+ children <- many (headline blocks inline (level + 1))
+ return $ do
+ title' <- title
+ contents' <- contents
+ children' <- sequence children
+ return Headline
+ { headlineLevel = level
+ , headlineTodoMarker = todoKw
+ , headlineText = title'
+ , headlineTags = tags
+ , headlineProperties = properties
+ , headlineContents = contents'
+ , headlineChildren = children'
+ }
+ where
+ endOfTitle :: Monad m => OrgParser m ()
+ endOfTitle = void . lookAhead $ optional headerTags *> newline
+
+ headerTags :: Monad m => OrgParser m [Tag]
+ headerTags = try $
+ let tag = many1 (alphaNum <|> oneOf "@%#_") <* char ':'
+ in map toTag <$> (skipSpaces *> char ':' *> many1 tag <* skipSpaces)
+
+-- | Convert an Org mode headline (i.e. a document tree) into pandoc's Blocks
+headlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
+headlineToBlocks hdln@Headline {..} = do
+ maxHeadlineLevels <- getExportSetting exportHeadlineLevels
+ case () of
+ _ | any isNoExportTag headlineTags -> return mempty
+ _ | any isArchiveTag headlineTags -> archivedHeadlineToBlocks hdln
+ _ | isCommentTitle headlineText -> return mempty
+ _ | headlineLevel >= maxHeadlineLevels -> headlineToHeaderWithList hdln
+ _ | otherwise -> headlineToHeaderWithContents hdln
+
+isNoExportTag :: Tag -> Bool
+isNoExportTag = (== toTag "noexport")
+
+isArchiveTag :: Tag -> Bool
+isArchiveTag = (== toTag "ARCHIVE")
+
+-- | Check if the title starts with COMMENT.
+-- FIXME: This accesses builder internals not intended for use in situations
+-- like these. Replace once keyword parsing is supported.
+isCommentTitle :: Inlines -> Bool
+isCommentTitle (B.toList -> (Str "COMMENT":_)) = True
+isCommentTitle _ = False
+
+archivedHeadlineToBlocks :: Monad m => Headline -> OrgParser m Blocks
+archivedHeadlineToBlocks hdln = do
+ archivedTreesOption <- getExportSetting exportArchivedTrees
+ case archivedTreesOption of
+ ArchivedTreesNoExport -> return mempty
+ ArchivedTreesExport -> headlineToHeaderWithContents hdln
+ ArchivedTreesHeadlineOnly -> headlineToHeader hdln
+
+headlineToHeaderWithList :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeaderWithList hdln@Headline {..} = do
+ maxHeadlineLevels <- getExportSetting exportHeadlineLevels
+ header <- headlineToHeader hdln
+ listElements <- mapM headlineToBlocks headlineChildren
+ let listBlock = if null listElements
+ then mempty
+ else B.orderedList listElements
+ let headerText = if maxHeadlineLevels == headlineLevel
+ then header
+ else flattenHeader header
+ return $ headerText <> headlineContents <> listBlock
+ where
+ flattenHeader :: Blocks -> Blocks
+ flattenHeader blks =
+ case B.toList blks of
+ (Header _ _ inlns:_) -> B.para (B.fromList inlns)
+ _ -> mempty
+
+headlineToHeaderWithContents :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeaderWithContents hdln@Headline {..} = do
+ header <- headlineToHeader hdln
+ childrenBlocks <- mconcat <$> mapM headlineToBlocks headlineChildren
+ return $ header <> headlineContents <> childrenBlocks
+
+headlineToHeader :: Monad m => Headline -> OrgParser m Blocks
+headlineToHeader Headline {..} = do
+ exportTodoKeyword <- getExportSetting exportWithTodoKeywords
+ exportTags <- getExportSetting exportWithTags
+ let todoText = if exportTodoKeyword
+ then case headlineTodoMarker of
+ Just kw -> todoKeywordToInlines kw <> B.space
+ Nothing -> mempty
+ else mempty
+ let text = todoText <> headlineText <>
+ if exportTags
+ then tagsToInlines headlineTags
+ else mempty
+ let propAttr = propertiesToAttr headlineProperties
+ attr <- registerHeader propAttr headlineText
+ return $ B.headerWith attr headlineLevel text
+
+todoKeyword :: Monad m => OrgParser m TodoMarker
+todoKeyword = try $ do
+ taskStates <- activeTodoMarkers <$> getState
+ let kwParser tdm = try (tdm <$ string (todoMarkerName tdm) <* spaceChar)
+ choice (map kwParser taskStates)
+
+todoKeywordToInlines :: TodoMarker -> Inlines
+todoKeywordToInlines tdm =
+ let todoText = todoMarkerName tdm
+ todoState = map toLower . show $ todoMarkerState tdm
+ classes = [todoState, todoText]
+ in B.spanWith (mempty, classes, mempty) (B.str todoText)
+
+propertiesToAttr :: Properties -> Attr
+propertiesToAttr properties =
+ let
+ toStringPair = fromKey *** fromValue
+ customIdKey = toPropertyKey "custom_id"
+ classKey = toPropertyKey "class"
+ unnumberedKey = toPropertyKey "unnumbered"
+ specialProperties = [customIdKey, classKey, unnumberedKey]
+ id' = maybe mempty fromValue . lookup customIdKey $ properties
+ cls = maybe mempty fromValue . lookup classKey $ properties
+ kvs' = map toStringPair . filter ((`notElem` specialProperties) . fst)
+ $ properties
+ isUnnumbered =
+ maybe False isNonNil . lookup unnumberedKey $ properties
+ in
+ (id', words cls ++ ["unnumbered" | isUnnumbered], kvs')
+
+tagsToInlines :: [Tag] -> Inlines
+tagsToInlines [] = mempty
+tagsToInlines tags =
+ (B.space <>) . mconcat . intersperse (B.str "\160") . map tagToInline $ tags
+ where
+ tagToInline :: Tag -> Inlines
+ tagToInline t = tagSpan t . B.smallcaps . B.str $ fromTag t
+
+-- | Wrap the given inline in a span, marking it as a tag.
+tagSpan :: Tag -> Inlines -> Inlines
+tagSpan t = B.spanWith ("", ["tag"], [("data-tag-name", fromTag t)])
+
+
+
+
+
+-- | Read a :PROPERTIES: drawer and return the key/value pairs contained
+-- within.
+propertiesDrawer :: Monad m => OrgParser m Properties
+propertiesDrawer = try $ do
+ drawerType <- drawerStart
+ guard $ map toUpper drawerType == "PROPERTIES"
+ manyTill property (try endOfDrawer)
+ where
+ property :: Monad m => OrgParser m (PropertyKey, PropertyValue)
+ property = try $ (,) <$> key <*> value
+
+ key :: Monad m => OrgParser m PropertyKey
+ key = fmap toPropertyKey . try $
+ skipSpaces *> char ':' *> many1Till nonspaceChar (char ':')
+
+ value :: Monad m => OrgParser m PropertyValue
+ value = fmap toPropertyValue . try $
+ skipSpaces *> manyTill anyChar (try $ skipSpaces *> newline)
+
+ endOfDrawer :: Monad m => OrgParser m String
+ endOfDrawer = try $
+ skipSpaces *> stringAnyCase ":END:" <* skipSpaces <* newline
diff --git a/src/Text/Pandoc/Readers/Org/ExportSettings.hs b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
index 1d6fdd7e1..11f0972d5 100644
--- a/src/Text/Pandoc/Readers/Org/ExportSettings.hs
+++ b/src/Text/Pandoc/Readers/Org/ExportSettings.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.ExportSettings
+ Copyright : © 2016–2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -71,7 +71,7 @@ exportSetting = choice
, ignoredSetting "pri"
, ignoredSetting "prop"
, ignoredSetting "stat"
- , ignoredSetting "tags"
+ , booleanSetting "tags" (\val es -> es { exportWithTags = val })
, ignoredSetting "tasks"
, ignoredSetting "tex"
, ignoredSetting "timestamp"
diff --git a/src/Text/Pandoc/Readers/Org/Inlines.hs b/src/Text/Pandoc/Readers/Org/Inlines.hs
index 64ffb8ef5..66273e05d 100644
--- a/src/Text/Pandoc/Readers/Org/Inlines.hs
+++ b/src/Text/Pandoc/Readers/Org/Inlines.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -18,8 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Inlines
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -48,7 +48,7 @@ import Text.Pandoc.Readers.LaTeX (inlineCommand, rawLaTeXInline)
import Text.TeXMath (DisplayType (..), readTeX, writePandoc)
import qualified Text.TeXMath.Readers.MathML.EntityMap as MathMLEntityMap
-import Control.Monad (guard, mplus, mzero, void, when)
+import Control.Monad (guard, mplus, mzero, unless, void, when)
import Control.Monad.Trans (lift)
import Data.Char (isAlphaNum, isSpace)
import Data.List (intersperse)
@@ -63,7 +63,7 @@ import Prelude hiding (sequence)
--
recordAnchorId :: PandocMonad m => String -> OrgParser m ()
recordAnchorId i = updateState $ \s ->
- s{ orgStateAnchorIds = i : (orgStateAnchorIds s) }
+ s{ orgStateAnchorIds = i : orgStateAnchorIds s }
pushToInlineCharStack :: PandocMonad m => Char -> OrgParser m ()
pushToInlineCharStack c = updateState $ \s ->
@@ -120,6 +120,7 @@ inline =
, superscript
, inlineLaTeX
, exportSnippet
+ , macro
, smart
, symbol
] <* (guard =<< newlinesCountWithinLimits)
@@ -183,7 +184,7 @@ cite = try $ berkeleyCite <|> do
, orgRefCite
, berkeleyTextualCite
]
- return $ (flip B.cite (B.text raw)) <$> cs
+ return $ flip B.cite (B.text raw) <$> cs
-- | A citation in Pandoc Org-mode style (@[prefix \@citekey suffix]@).
pandocOrgCite :: PandocMonad m => OrgParser m (F [Citation])
@@ -208,7 +209,7 @@ normalOrgRefCite = try $ do
orgRefCiteList :: PandocMonad m => CitationMode -> OrgParser m (F Citation)
orgRefCiteList citeMode = try $ do
key <- orgRefCiteKey
- returnF $ Citation
+ returnF Citation
{ citationId = key
, citationPrefix = mempty
, citationSuffix = mempty
@@ -231,11 +232,11 @@ berkeleyCite = try $ do
return $
if parens
then toCite
- . maybe id (\p -> alterFirst (prependPrefix p)) prefix
- . maybe id (\s -> alterLast (appendSuffix s)) suffix
+ . maybe id (alterFirst . prependPrefix) prefix
+ . maybe id (alterLast . appendSuffix) suffix
$ citationList
else maybe mempty (<> " ") prefix
- <> (toListOfCites $ map toInTextMode citationList)
+ <> toListOfCites (map toInTextMode citationList)
<> maybe mempty (", " <>) suffix
where
toCite :: [Citation] -> Inlines
@@ -249,7 +250,7 @@ berkeleyCite = try $ do
alterFirst, alterLast :: (a -> a) -> [a] -> [a]
alterFirst _ [] = []
- alterFirst f (c:cs) = (f c):cs
+ alterFirst f (c:cs) = f c : cs
alterLast f = reverse . alterFirst f . reverse
prependPrefix, appendSuffix :: Inlines -> Citation -> Citation
@@ -270,7 +271,7 @@ berkeleyCitationList = try $ do
skipSpaces
commonPrefix <- optionMaybe (try $ citationListPart <* char ';')
citations <- citeList
- commonSuffix <- optionMaybe (try $ citationListPart)
+ commonSuffix <- optionMaybe (try citationListPart)
char ']'
return (BerkeleyCitationList parens
<$> sequence commonPrefix
@@ -338,8 +339,15 @@ linkLikeOrgRefCite = try $ do
-- | Read a citation key. The characters allowed in citation keys are taken
-- from the `org-ref-cite-re` variable in `org-ref.el`.
orgRefCiteKey :: PandocMonad m => OrgParser m String
-orgRefCiteKey = try . many1 . satisfy $ \c ->
- isAlphaNum c || c `elem` ("-_:\\./"::String)
+orgRefCiteKey =
+ let citeKeySpecialChars = "-_:\\./," :: String
+ isCiteKeySpecialChar c = c `elem` citeKeySpecialChars
+ isCiteKeyChar c = isAlphaNum c || isCiteKeySpecialChar c
+ endOfCitation = try $ do
+ many $ satisfy isCiteKeySpecialChar
+ satisfy $ not . isCiteKeyChar
+ in try $ satisfy isCiteKeyChar `many1Till` lookAhead endOfCitation
+
-- | Supported citation types. Only a small subset of org-ref types is
-- supported for now. TODO: rewrite this, use LaTeX reader as template.
@@ -365,15 +373,16 @@ citation = try $ do
return $ do
x <- pref
y <- suff
- return $ Citation{ citationId = key
- , citationPrefix = B.toList x
- , citationSuffix = B.toList y
- , citationMode = if suppress_author
- then SuppressAuthor
- else NormalCitation
- , citationNoteNum = 0
- , citationHash = 0
- }
+ return Citation
+ { citationId = key
+ , citationPrefix = B.toList x
+ , citationSuffix = B.toList y
+ , citationMode = if suppress_author
+ then SuppressAuthor
+ else NormalCitation
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
where
prefix = trimInlinesF . mconcat <$>
manyTill inline (char ']' <|> (']' <$ lookAhead citeKey))
@@ -395,7 +404,7 @@ inlineNote = try $ do
ref <- many alphaNum
char ':'
note <- fmap B.para . trimInlinesF . mconcat <$> many1Till inline (char ']')
- when (not $ null ref) $
+ unless (null ref) $
addToNotesTable ("fn:" ++ ref, note)
return $ B.note <$> note
@@ -405,7 +414,7 @@ referencedNote = try $ do
return $ do
notes <- asksF orgStateNotes'
case lookup ref notes of
- Nothing -> return $ B.str $ "[" ++ ref ++ "]"
+ Nothing -> return . B.str $ "[" ++ ref ++ "]"
Just contents -> do
st <- askF
let contents' = runF contents st{ orgStateNotes' = [] }
@@ -429,7 +438,7 @@ explicitOrImageLink = try $ do
src <- srcF
case cleanLinkString title of
Just imgSrc | isImageFilename imgSrc ->
- pure $ B.link src "" $ B.image imgSrc mempty mempty
+ pure . B.link src "" $ B.image imgSrc mempty mempty
_ ->
linkToInlinesF src =<< title'
@@ -686,13 +695,13 @@ mathEnd c = try $ do
return res
-enclosedInlines :: PandocMonad m => OrgParser m a
+enclosedInlines :: (PandocMonad m, Show b) => OrgParser m a
-> OrgParser m b
-> OrgParser m (F Inlines)
enclosedInlines start end = try $
trimInlinesF . mconcat <$> enclosed start end inline
-enclosedRaw :: PandocMonad m => OrgParser m a
+enclosedRaw :: (PandocMonad m, Show b) => OrgParser m a
-> OrgParser m b
-> OrgParser m String
enclosedRaw start end = try $
@@ -771,7 +780,7 @@ notAfterForbiddenBorderChar = do
-- | Read a sub- or superscript expression
subOrSuperExpr :: PandocMonad m => OrgParser m (F Inlines)
subOrSuperExpr = try $
- choice [ id <$> charsInBalanced '{' '}' (noneOf "\n\r")
+ choice [ charsInBalanced '{' '}' (noneOf "\n\r")
, enclosing ('(', ')') <$> charsInBalanced '(' ')' (noneOf "\n\r")
, simpleSubOrSuperString
] >>= parseFromString (mconcat <$> many inline)
@@ -809,7 +818,7 @@ inlineLaTeX = try $ do
enableExtension Ext_raw_tex (readerExtensions def) } }
texMathToPandoc :: String -> Maybe [Inline]
- texMathToPandoc cs = (maybeRight $ readTeX cs) >>= writePandoc DisplayInline
+ texMathToPandoc cs = maybeRight (readTeX cs) >>= writePandoc DisplayInline
maybeRight :: Either a b -> Maybe b
maybeRight = either (const Nothing) Just
@@ -839,26 +848,49 @@ exportSnippet = try $ do
snippet <- manyTill anyChar (try $ string "@@")
returnF $ B.rawInline format snippet
+macro :: PandocMonad m => OrgParser m (F Inlines)
+macro = try $ do
+ recursionDepth <- orgStateMacroDepth <$> getState
+ guard $ recursionDepth < 15
+ string "{{{"
+ name <- many alphaNum
+ args <- ([] <$ string "}}}")
+ <|> char '(' *> argument `sepBy` char ',' <* eoa
+ expander <- lookupMacro name <$> getState
+ case expander of
+ Nothing -> mzero
+ Just fn -> do
+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth + 1 }
+ res <- parseFromString (mconcat <$> many inline) $ fn args
+ updateState $ \s -> s { orgStateMacroDepth = recursionDepth }
+ return res
+ where
+ argument = many $ notFollowedBy eoa *> noneOf ","
+ eoa = string ")}}}"
+
smart :: PandocMonad m => OrgParser m (F Inlines)
-smart = do
- guardEnabled Ext_smart
- doubleQuoted <|> singleQuoted <|>
- choice (map (return <$>) [orgApostrophe, orgDash, orgEllipses])
+smart = choice [doubleQuoted, singleQuoted, orgApostrophe, orgDash, orgEllipses]
where
orgDash = do
- guard =<< getExportSetting exportSpecialStrings
- dash <* updatePositions '-'
+ guardOrSmartEnabled =<< getExportSetting exportSpecialStrings
+ pure <$> dash <* updatePositions '-'
orgEllipses = do
- guard =<< getExportSetting exportSpecialStrings
- ellipses <* updatePositions '.'
- orgApostrophe =
- (char '\'' <|> char '\8217') <* updateLastPreCharPos
- <* updateLastForbiddenCharPos
- *> return (B.str "\x2019")
+ guardOrSmartEnabled =<< getExportSetting exportSpecialStrings
+ pure <$> ellipses <* updatePositions '.'
+ orgApostrophe = do
+ guardEnabled Ext_smart
+ (char '\'' <|> char '\8217') <* updateLastPreCharPos
+ <* updateLastForbiddenCharPos
+ returnF (B.str "\x2019")
+
+guardOrSmartEnabled :: PandocMonad m => Bool -> OrgParser m ()
+guardOrSmartEnabled b = do
+ smartExtension <- extensionEnabled Ext_smart <$> getOption readerExtensions
+ guard (b || smartExtension)
singleQuoted :: PandocMonad m => OrgParser m (F Inlines)
singleQuoted = try $ do
- guard =<< getExportSetting exportSmartQuotes
+ guardOrSmartEnabled =<< getExportSetting exportSmartQuotes
singleQuoteStart
updatePositions '\''
withQuoteContext InSingleQuote $
@@ -870,10 +902,13 @@ singleQuoted = try $ do
-- in the same paragraph.
doubleQuoted :: PandocMonad m => OrgParser m (F Inlines)
doubleQuoted = try $ do
- guard =<< getExportSetting exportSmartQuotes
+ guardOrSmartEnabled =<< getExportSetting exportSmartQuotes
doubleQuoteStart
updatePositions '"'
contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
- (withQuoteContext InDoubleQuote $ (doubleQuoteEnd <* updateLastForbiddenCharPos) >> return
- (fmap B.doubleQuoted . trimInlinesF $ contents))
- <|> (return $ return (B.str "\8220") <> contents)
+ let doubleQuotedContent = withQuoteContext InDoubleQuote $ do
+ doubleQuoteEnd
+ updateLastForbiddenCharPos
+ return . fmap B.doubleQuoted . trimInlinesF $ contents
+ let leftQuoteAndContent = return $ pure (B.str "\8220") <> contents
+ doubleQuotedContent <|> leftQuoteAndContent
diff --git a/src/Text/Pandoc/Readers/Org/Meta.hs b/src/Text/Pandoc/Readers/Org/Meta.hs
index 7938fc6c6..d22902eae 100644
--- a/src/Text/Pandoc/Readers/Org/Meta.hs
+++ b/src/Text/Pandoc/Readers/Org/Meta.hs
@@ -44,7 +44,7 @@ import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
-import Control.Monad (mzero, void)
+import Control.Monad (mzero, void, when)
import Data.Char (toLower)
import Data.List (intersperse)
import qualified Data.Map as M
@@ -75,14 +75,16 @@ declarationLine :: PandocMonad m => OrgParser m ()
declarationLine = try $ do
key <- map toLower <$> metaKey
(key', value) <- metaValue key
- updateState $ \st -> st { orgStateMeta = B.setMeta key' <$> value <*> orgStateMeta st }
+ let addMetaValue st =
+ st { orgStateMeta = B.setMeta key' <$> value <*> orgStateMeta st }
+ when (key' /= "results") $ updateState addMetaValue
metaKey :: Monad m => OrgParser m String
metaKey = map toLower <$> many1 (noneOf ": \n\r")
<* char ':'
<* skipSpaces
-metaValue :: PandocMonad m => String -> OrgParser m (String, (F MetaValue))
+metaValue :: PandocMonad m => String -> OrgParser m (String, F MetaValue)
metaValue key =
let inclKey = "header-includes"
in case key of
@@ -109,7 +111,7 @@ metaInlines = fmap (MetaInlines . B.toList) <$> inlinesTillNewline
metaInlinesCommaSeparated :: PandocMonad m => OrgParser m (F MetaValue)
metaInlinesCommaSeparated = do
- itemStrs <- (many1 (noneOf ",\n")) `sepBy1` (char ',')
+ itemStrs <- many1 (noneOf ",\n") `sepBy1` char ','
newline
items <- mapM (parseFromString inlinesTillNewline . (++ "\n")) itemStrs
let toMetaInlines = MetaInlines . B.toList
@@ -151,6 +153,7 @@ optionLine = try $ do
"todo" -> todoSequence >>= updateState . registerTodoSequence
"seq_todo" -> todoSequence >>= updateState . registerTodoSequence
"typ_todo" -> todoSequence >>= updateState . registerTodoSequence
+ "macro" -> macroDefinition >>= updateState . registerMacro
_ -> mzero
addLinkFormat :: Monad m => String
@@ -160,7 +163,7 @@ addLinkFormat key formatter = updateState $ \s ->
let fs = orgStateLinkFormatters s
in s{ orgStateLinkFormatters = M.insert key formatter fs }
-parseLinkFormat :: Monad m => OrgParser m ((String, String -> String))
+parseLinkFormat :: Monad m => OrgParser m (String, String -> String)
parseLinkFormat = try $ do
linkType <- (:) <$> letter <*> many (alphaNum <|> oneOf "-_") <* skipSpaces
linkSubst <- parseFormat
@@ -169,8 +172,7 @@ parseLinkFormat = try $ do
-- | An ad-hoc, single-argument-only implementation of a printf-style format
-- parser.
parseFormat :: Monad m => OrgParser m (String -> String)
-parseFormat = try $ do
- replacePlain <|> replaceUrl <|> justAppend
+parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
where
-- inefficient, but who cares
replacePlain = try $ (\x -> concat . flip intersperse x)
@@ -218,3 +220,27 @@ todoSequence = try $ do
let todoMarkers = map (TodoMarker Todo) todo
doneMarkers = map (TodoMarker Done) done
in todoMarkers ++ doneMarkers
+
+macroDefinition :: Monad m => OrgParser m (String, [String] -> String)
+macroDefinition = try $ do
+ macroName <- many1 nonspaceChar <* skipSpaces
+ firstPart <- expansionPart
+ (elemOrder, parts) <- unzip <$> many ((,) <$> placeholder <*> expansionPart)
+ let expander = mconcat . alternate (firstPart:parts) . reorder elemOrder
+ return (macroName, expander)
+ where
+ placeholder :: Monad m => OrgParser m Int
+ placeholder = try . fmap read $ char '$' *> many1 digit
+
+ expansionPart :: Monad m => OrgParser m String
+ expansionPart = try $ many (notFollowedBy placeholder *> noneOf "\n\r")
+
+ alternate :: [a] -> [a] -> [a]
+ alternate [] ys = ys
+ alternate xs [] = xs
+ alternate (x:xs) (y:ys) = x : y : alternate xs ys
+
+ reorder :: [Int] -> [String] -> [String]
+ reorder perm xs =
+ let element n = take 1 $ drop (n - 1) xs
+ in concatMap element perm
diff --git a/src/Text/Pandoc/Readers/Org/ParserState.hs b/src/Text/Pandoc/Readers/Org/ParserState.hs
index bdd1dc951..92f868516 100644
--- a/src/Text/Pandoc/Readers/Org/ParserState.hs
+++ b/src/Text/Pandoc/Readers/Org/ParserState.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE GeneralizedNewtypeDeriving #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -20,8 +19,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.ParserState
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -39,6 +38,9 @@ module Text.Pandoc.Readers.Org.ParserState
, TodoState (..)
, activeTodoMarkers
, registerTodoSequence
+ , MacroExpander
+ , lookupMacro
+ , registerMacro
, F
, askF
, asksF
@@ -58,14 +60,14 @@ import qualified Data.Set as Set
import Text.Pandoc.Builder (Blocks, Inlines)
import Text.Pandoc.Definition (Meta (..), nullMeta)
-import Text.Pandoc.Options (ReaderOptions (..))
import Text.Pandoc.Logging
-import Text.Pandoc.Parsing (HasHeaderMap (..), HasIdentifierList (..),
- HasLogMessages (..),
- HasLastStrPosition (..), HasQuoteContext (..),
+import Text.Pandoc.Options (ReaderOptions (..))
+import Text.Pandoc.Parsing (Future, HasHeaderMap (..), HasIdentifierList (..),
+ HasIncludeFiles (..), HasLastStrPosition (..),
+ HasLogMessages (..), HasQuoteContext (..),
HasReaderOptions (..), ParserContext (..),
- QuoteContext (..), SourcePos, Future,
- askF, asksF, returnF, runF, trimInlinesF)
+ QuoteContext (..), SourcePos, askF, asksF, returnF,
+ runF, trimInlinesF)
-- | This is used to delay evaluation until all relevant information has been
-- parsed and made available in the parser state.
@@ -78,6 +80,8 @@ type OrgNoteTable = [OrgNoteRecord]
-- | Map of functions for link transformations. The map key is refers to the
-- link-type, the corresponding function transforms the given link string.
type OrgLinkFormatters = M.Map String (String -> String)
+-- | Macro expander function
+type MacroExpander = [String] -> String
-- | The states in which a todo item can be
data TodoState = Todo | Done
@@ -101,10 +105,13 @@ data OrgParserState = OrgParserState
, orgStateExportSettings :: ExportSettings
, orgStateHeaderMap :: M.Map Inlines String
, orgStateIdentifiers :: Set.Set String
+ , orgStateIncludeFiles :: [String]
, orgStateLastForbiddenCharPos :: Maybe SourcePos
, orgStateLastPreCharPos :: Maybe SourcePos
, orgStateLastStrPos :: Maybe SourcePos
, orgStateLinkFormatters :: OrgLinkFormatters
+ , orgStateMacros :: M.Map String MacroExpander
+ , orgStateMacroDepth :: Int
, orgStateMeta :: F Meta
, orgStateNotes' :: OrgNoteTable
, orgStateOptions :: ReaderOptions
@@ -141,6 +148,12 @@ instance HasLogMessages OrgParserState where
addLogMessage msg st = st{ orgLogMessages = msg : orgLogMessages st }
getLogMessages st = reverse $ orgLogMessages st
+instance HasIncludeFiles OrgParserState where
+ getIncludeFiles = orgStateIncludeFiles
+ addIncludeFile f st = st { orgStateIncludeFiles = f : orgStateIncludeFiles st }
+ dropLatestIncludeFile st =
+ st { orgStateIncludeFiles = drop 1 $ orgStateIncludeFiles st }
+
instance Default OrgParserState where
def = defaultOrgParserState
@@ -152,10 +165,13 @@ defaultOrgParserState = OrgParserState
, orgStateExportSettings = def
, orgStateHeaderMap = M.empty
, orgStateIdentifiers = Set.empty
+ , orgStateIncludeFiles = []
, orgStateLastForbiddenCharPos = Nothing
, orgStateLastPreCharPos = Nothing
, orgStateLastStrPos = Nothing
, orgStateLinkFormatters = M.empty
+ , orgStateMacros = M.empty
+ , orgStateMacroDepth = 0
, orgStateMeta = return nullMeta
, orgStateNotes' = []
, orgStateOptions = def
@@ -185,6 +201,15 @@ activeTodoSequences st =
activeTodoMarkers :: OrgParserState -> TodoSequence
activeTodoMarkers = concat . activeTodoSequences
+lookupMacro :: String -> OrgParserState -> Maybe MacroExpander
+lookupMacro macroName = M.lookup macroName . orgStateMacros
+
+registerMacro :: (String, MacroExpander) -> OrgParserState -> OrgParserState
+registerMacro (name, expander) st =
+ let curMacros = orgStateMacros st
+ in st{ orgStateMacros = M.insert name expander curMacros }
+
+
--
-- Export Settings
@@ -213,6 +238,7 @@ data ExportSettings = ExportSettings
, exportWithAuthor :: Bool -- ^ Include author in final meta-data
, exportWithCreator :: Bool -- ^ Include creator in final meta-data
, exportWithEmail :: Bool -- ^ Include email in final meta-data
+ , exportWithTags :: Bool -- ^ Keep tags as part of headlines
, exportWithTodoKeywords :: Bool -- ^ Keep TODO keywords in headers
}
@@ -225,11 +251,12 @@ defaultExportSettings = ExportSettings
, exportDrawers = Left ["LOGBOOK"]
, exportEmphasizedText = True
, exportHeadlineLevels = 3
- , exportSmartQuotes = True
+ , exportSmartQuotes = False
, exportSpecialStrings = True
, exportSubSuperscripts = True
, exportWithAuthor = True
, exportWithCreator = True
, exportWithEmail = True
+ , exportWithTags = True
, exportWithTodoKeywords = True
}
diff --git a/src/Text/Pandoc/Readers/Org/Parsing.hs b/src/Text/Pandoc/Readers/Org/Parsing.hs
index 464ef9ca6..3273c92e4 100644
--- a/src/Text/Pandoc/Readers/Org/Parsing.hs
+++ b/src/Text/Pandoc/Readers/Org/Parsing.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -17,8 +17,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Parsing
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -31,6 +31,8 @@ functions are adapted to Org-mode specific functionality.
module Text.Pandoc.Readers.Org.Parsing
( OrgParser
, anyLine
+ , anyLineNewline
+ , indentWith
, blanklines
, newline
, parseFromString
@@ -70,6 +72,8 @@ module Text.Pandoc.Readers.Org.Parsing
, dash
, ellipses
, citeKey
+ , gridTableWith
+ , insertIncludedFileF
-- * Re-exports from Text.Pandoc.Parsec
, runParser
, runParserT
diff --git a/src/Text/Pandoc/Readers/Org/Shared.hs b/src/Text/Pandoc/Readers/Org/Shared.hs
index f89ce6732..952082ec1 100644
--- a/src/Text/Pandoc/Readers/Org/Shared.hs
+++ b/src/Text/Pandoc/Readers/Org/Shared.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2014-2016 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
+Copyright (C) 2014-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -18,8 +18,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
{- |
- Module : Text.Pandoc.Readers.Org.Options
- Copyright : Copyright (C) 2014-2016 Albert Krewinkel
+ Module : Text.Pandoc.Readers.Org.Shared
+ Copyright : Copyright (C) 2014-2017 Albert Krewinkel
License : GNU GPL, version 2 or above
Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -56,7 +56,7 @@ cleanLinkString s =
'.':'/':_ -> Just s -- relative path
'.':'.':'/':_ -> Just s -- relative path
-- Relative path or URL (file schema)
- 'f':'i':'l':'e':':':s' -> Just $ if ("//" `isPrefixOf` s') then s else s'
+ 'f':'i':'l':'e':':':s' -> Just $ if "//" `isPrefixOf` s' then s else s'
_ | isUrl s -> Just s -- URL
_ -> Nothing
where
diff --git a/src/Text/Pandoc/Readers/RST.hs b/src/Text/Pandoc/Readers/RST.hs
index 7564998ff..fb5f6f2d4 100644
--- a/src/Text/Pandoc/Readers/RST.hs
+++ b/src/Text/Pandoc/Readers/RST.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Readers.RST
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -32,10 +32,11 @@ Conversion from reStructuredText to 'Pandoc' document.
-}
module Text.Pandoc.Readers.RST ( readRST ) where
import Control.Monad (guard, liftM, mzero, when)
+import Control.Monad.Identity (Identity(..))
import Control.Monad.Except (throwError)
import Data.Char (isHexDigit, isSpace, toLower, toUpper)
-import Data.List (deleteFirstsBy, findIndex, intercalate, isInfixOf, isSuffixOf,
- nub, sort, transpose, union)
+import Data.List (deleteFirstsBy, findIndex, intercalate, isInfixOf,
+ isSuffixOf, nub, sort, transpose, union)
import qualified Data.Map as M
import Data.Maybe (fromMaybe, isJust)
import Data.Monoid ((<>))
@@ -52,20 +53,22 @@ import Text.Pandoc.Options
import Text.Pandoc.Parsing
import Text.Pandoc.Shared
import Text.Printf (printf)
+import Data.Text (Text)
+import qualified Data.Text as T
-- TODO:
-- [ ] .. parsed-literal
-- [ ] :widths: attribute in .. table
-- [ ] .. csv-table
--- [ ] .. list-table
-- | Parse reStructuredText string and return Pandoc document.
readRST :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readRST opts s = do
- parsed <- (readWithM parseRST) def{ stateOptions = opts } (s ++ "\n\n")
+ parsed <- (readWithM parseRST) def{ stateOptions = opts }
+ (T.unpack s ++ "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -131,7 +134,10 @@ metaFromDefList ds meta = adjustAuthors $ foldr f meta ds
adjustAuthors (Meta metamap) = Meta $ M.adjust splitAuthors "author"
$ M.adjust toPlain "date"
$ M.adjust toPlain "title"
- $ M.mapKeys (\k -> if k == "authors" then "author" else k)
+ $ M.mapKeys (\k ->
+ if k == "authors"
+ then "author"
+ else k)
$ metamap
toPlain (MetaBlocks [Para xs]) = MetaInlines xs
toPlain x = x
@@ -193,7 +199,7 @@ parseRST = do
parseCitation :: PandocMonad m
=> (String, String) -> RSTParser m (Inlines, [Blocks])
parseCitation (ref, raw) = do
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
return $ (B.spanWith (ref, ["citation-label"], []) (B.str ref),
[contents])
@@ -243,7 +249,7 @@ fieldListItem :: PandocMonad m => Int -> RSTParser m (Inlines, [Blocks])
fieldListItem minIndent = try $ do
(name, raw) <- rawFieldListItem minIndent
term <- parseInlineFromString name
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
optional blanklines
return (term, [contents])
@@ -442,7 +448,7 @@ blockQuote :: PandocMonad m => RSTParser m Blocks
blockQuote = do
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ raw ++ "\n\n"
+ contents <- parseFromString' parseBlocks $ raw ++ "\n\n"
return $ B.blockQuote contents
{-
@@ -530,7 +536,7 @@ definitionListItem = try $ do
term <- trimInlines . mconcat <$> many1Till inline endline
raw <- indentedBlock
-- parse the extracted block, which may contain various block elements:
- contents <- parseFromString parseBlocks $ raw ++ "\n"
+ contents <- parseFromString' parseBlocks $ raw ++ "\n"
return (term, [contents])
definitionList :: PandocMonad m => RSTParser m Blocks
@@ -558,26 +564,16 @@ listLine :: Monad m => Int -> RSTParser m [Char]
listLine markerLength = try $ do
notFollowedBy blankline
indentWith markerLength
- line <- anyLine
- return $ line ++ "\n"
-
--- indent by specified number of spaces (or equiv. tabs)
-indentWith :: Monad m => Int -> RSTParser m [Char]
-indentWith num = do
- tabStop <- getOption readerTabStop
- if (num < tabStop)
- then count num (char ' ')
- else choice [ try (count num (char ' ')),
- (try (char '\t' >> count (num - tabStop) (char ' '))) ]
+ anyLineNewline
-- parse raw text for one list item, excluding start marker and continuations
rawListItem :: Monad m => RSTParser m Int
-> RSTParser m (Int, [Char])
rawListItem start = try $ do
markerLength <- start
- firstLine <- anyLine
+ firstLine <- anyLineNewline
restLines <- many (listLine markerLength)
- return (markerLength, (firstLine ++ "\n" ++ (concat restLines)))
+ return (markerLength, firstLine ++ concat restLines)
-- continuation of a list item - indented and separated by blankline or
-- (in compact lists) endline.
@@ -602,13 +598,17 @@ listItem start = try $ do
let oldContext = stateParserContext state
setState $ state {stateParserContext = ListItemState}
-- parse the extracted block, which may itself contain block elements
- parsed <- parseFromString parseBlocks $ concat (first:rest) ++ "\n"
+ parsed <- parseFromString' parseBlocks $ concat (first:rest) ++ "\n"
updateState (\st -> st {stateParserContext = oldContext})
return $ case B.toList parsed of
- [Para xs] -> B.singleton $ Plain xs
- [Para xs, BulletList ys] -> B.fromList [Plain xs, BulletList ys]
- [Para xs, OrderedList s ys] -> B.fromList [Plain xs, OrderedList s ys]
- [Para xs, DefinitionList ys] -> B.fromList [Plain xs, DefinitionList ys]
+ [Para xs] ->
+ B.singleton $ Plain xs
+ [Para xs, BulletList ys] ->
+ B.fromList [Plain xs, BulletList ys]
+ [Para xs, OrderedList s ys] ->
+ B.fromList [Plain xs, OrderedList s ys]
+ [Para xs, DefinitionList ys] ->
+ B.fromList [Plain xs, DefinitionList ys]
_ -> parsed
orderedList :: PandocMonad m => RSTParser m Blocks
@@ -685,22 +685,23 @@ directive' = do
(lengthToDim . filter (not . isSpace))
case label of
"table" -> tableDirective top fields body'
+ "list-table" -> listTableDirective top fields body'
"line-block" -> lineBlockDirective body'
"raw" -> return $ B.rawBlock (trim top) (stripTrailingNewlines body)
"role" -> addNewRole top $ map (\(k,v) -> (k, trim v)) fields
- "container" -> parseFromString parseBlocks body'
+ "container" -> parseFromString' parseBlocks body'
"replace" -> B.para <$> -- consumed by substKey
parseInlineFromString (trim top)
"unicode" -> B.para <$> -- consumed by substKey
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'
+ "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 <$> parseInlineFromString top
_ | label `elem` ["attention","caution","danger","error","hint",
"important","note","tip","warning","admonition"] ->
- do bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
+ do bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
let lab = case label of
"admonition" -> mempty
(l:ls) -> B.divWith ("",["admonition-title"],[])
@@ -713,11 +714,11 @@ directive' = do
(trim top ++ if null subtit
then ""
else (": " ++ subtit))
- bod <- parseFromString parseBlocks body'
+ bod <- parseFromString' parseBlocks body'
return $ B.divWith ("",["sidebar"],[]) $ tit <> bod
"topic" ->
do tit <- B.para . B.strong <$> parseInlineFromString top
- bod <- parseFromString parseBlocks body'
+ bod <- parseFromString' parseBlocks body'
return $ B.divWith ("",["topic"],[]) $ tit <> bod
"default-role" -> mempty <$ updateState (\s ->
s { stateRstDefaultRole =
@@ -733,9 +734,10 @@ directive' = do
"math" -> return $ B.para $ mconcat $ map B.displayMath
$ toChunks $ top ++ "\n\n" ++ body
"figure" -> do
- (caption, legend) <- parseFromString extractCaption body'
+ (caption, legend) <- parseFromString' extractCaption body'
let src = escapeURI $ trim top
- return $ B.para (B.imageWith (imgAttr "figclass") src "fig:" caption) <> legend
+ return $ B.para (B.imageWith (imgAttr "figclass") src "fig:"
+ caption) <> legend
"image" -> do
let src = escapeURI $ trim top
let alt = B.str $ maybe "image" trim $ lookup "alt" fields
@@ -746,38 +748,74 @@ directive' = do
$ B.imageWith attr src "" alt
Nothing -> B.imageWith attr src "" alt
"class" -> do
- let attrs = ("", (splitBy isSpace $ trim top), map (\(k,v) -> (k, trimr v)) fields)
+ 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'
+ _ -> parseFromString' parseBlocks body'
return $ B.divWith attrs children
other -> do
pos <- getPosition
logMessage $ SkippedContent (".. " ++ other) pos
- bod <- parseFromString parseBlocks $ top ++ "\n\n" ++ body'
+ bod <- parseFromString' parseBlocks $ top ++ "\n\n" ++ body'
return $ B.divWith ("",[other],[]) bod
tableDirective :: PandocMonad m
=> String -> [(String, String)] -> String -> RSTParser m Blocks
tableDirective top _fields body = do
- bs <- parseFromString parseBlocks body
+ bs <- parseFromString' parseBlocks body
case B.toList bs of
[Table _ aligns' widths' header' rows'] -> do
- title <- parseFromString (trimInlines . mconcat <$> many inline) top
+ title <- parseFromString' (trimInlines . mconcat <$> many inline) top
-- TODO widths
-- align is not applicable since we can't represent whole table align
return $ B.singleton $ Table (B.toList title)
aligns' widths' header' rows'
_ -> return mempty
+
+-- TODO: :stub-columns:.
+-- Only the first row becomes the header even if header-rows: > 1,
+-- since Pandoc doesn't support a table with multiple header rows.
+-- We don't need to parse :align: as it represents the whole table align.
+listTableDirective :: PandocMonad m
+ => String -> [(String, String)] -> String
+ -> RSTParser m Blocks
+listTableDirective top fields body = do
+ bs <- parseFromString' parseBlocks body
+ title <- parseFromString' (trimInlines . mconcat <$> many inline) top
+ let rows = takeRows $ B.toList bs
+ headerRowsNum = fromMaybe (0 :: Int) $
+ lookup "header-rows" fields >>= safeRead
+ (headerRow,bodyRows,numOfCols) = case rows of
+ x:xs -> if headerRowsNum > 0
+ then (x, xs, length x)
+ else ([], rows, length x)
+ _ -> ([],[],0)
+ widths = case trim <$> lookup "widths" fields of
+ Just "auto" -> replicate numOfCols 0
+ Just specs -> normWidths $ map (fromMaybe (0 :: Double) . safeRead) $
+ splitBy (`elem` (" ," :: String)) specs
+ _ -> replicate numOfCols 0
+ return $ B.table title
+ (zip (replicate numOfCols AlignDefault) widths)
+ headerRow
+ bodyRows
+ where takeRows [BulletList rows] = map takeCells rows
+ takeRows _ = []
+ takeCells [BulletList cells] = map B.fromList cells
+ takeCells _ = []
+ normWidths ws = map (/ max 1 (sum ws)) ws
+
-- TODO:
-- - Only supports :format: fields with a single format for :raw: roles,
-- change Text.Pandoc.Definition.Format to fix
-addNewRole :: PandocMonad m => String -> [(String, String)] -> RSTParser m Blocks
+addNewRole :: PandocMonad m
+ => String -> [(String, String)] -> RSTParser m Blocks
addNewRole roleString fields = do
pos <- getPosition
- (role, parentRole) <- parseFromString inheritedRole roleString
+ (role, parentRole) <- parseFromString' inheritedRole roleString
customRoles <- stateRstCustomRoles <$> getState
let getBaseRole (r, f, a) roles =
case M.lookup r roles of
@@ -804,7 +842,8 @@ addNewRole roleString fields = do
SkippedContent ":format: [because parent of role is not :raw:]" pos
_ -> logMessage $ SkippedContent (":" ++ key ++ ":") pos
when (parentRole == "raw" && countKeys "format" > 1) $
- logMessage $ SkippedContent ":format: [after first in definition of role]"
+ logMessage $ SkippedContent
+ ":format: [after first in definition of role]"
pos
when (parentRole == "code" && countKeys "language" > 1) $
logMessage $ SkippedContent
@@ -819,7 +858,8 @@ addNewRole roleString fields = do
where
countKeys k = length . filter (== k) . map fst $ fields
inheritedRole =
- (,) <$> roleName <*> ((char '(' *> roleName <* char ')') <|> pure "span")
+ (,) <$> roleName <*> ((char '(' *> roleName <* char ')')
+ <|> pure "span")
-- Can contain character codes as decimal numbers or
@@ -996,7 +1036,8 @@ substKey = try $ do
[Para ils] -> return $ B.fromList ils
_ -> mzero
let key = toKey $ stripFirstAndLast ref
- updateState $ \s -> s{ stateSubstitutions = M.insert key il $ stateSubstitutions s }
+ updateState $ \s -> s{ stateSubstitutions =
+ M.insert key il $ stateSubstitutions s }
anonymousKey :: Monad m => RSTParser m ()
anonymousKey = try $ do
@@ -1005,7 +1046,8 @@ anonymousKey = try $ do
pos <- getPosition
let key = toKey $ "_" ++ printf "%09d" (sourceLine pos)
--TODO: parse width, height, class and name attributes
- updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $ stateKeys s }
+ updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
+ stateKeys s }
stripTicks :: String -> String
stripTicks = reverse . stripTick . reverse . stripTick
@@ -1020,7 +1062,8 @@ regularKey = try $ do
src <- targetURI
let key = toKey $ stripTicks ref
--TODO: parse width, height, class and name attributes
- updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $ stateKeys s }
+ updateState $ \s -> s { stateKeys = M.insert key ((src,""), nullAttr) $
+ stateKeys s }
headerBlock :: PandocMonad m => RSTParser m [Char]
headerBlock = do
@@ -1087,7 +1130,7 @@ simpleTableRow indices = do
let cols = map unlines . transpose $ firstLine : conLines ++
[replicate (length indices) ""
| not (null conLines)]
- mapM (parseFromString parseBlocks) cols
+ mapM (parseFromString' parseBlocks) cols
simpleTableSplitLine :: [Int] -> String -> [String]
simpleTableSplitLine indices line =
@@ -1110,7 +1153,7 @@ simpleTableHeader headless = try $ do
let rawHeads = if headless
then replicate (length dashes) ""
else simpleTableSplitLine indices rawContent
- heads <- mapM (parseFromString (mconcat <$> many plain)) $
+ heads <- mapM (parseFromString' (mconcat <$> many plain)) $
map trim rawHeads
return (heads, aligns, indices)
@@ -1119,8 +1162,12 @@ simpleTable :: PandocMonad m
=> Bool -- ^ Headerless table
-> RSTParser m Blocks
simpleTable headless = do
- tbl <- tableWith (simpleTableHeader headless) simpleTableRow
- sep simpleTableFooter
+ let wrapIdFst (a, b, c) = (Identity a, b, c)
+ wrapId = fmap Identity
+ tbl <- runIdentity <$> tableWith
+ (wrapIdFst <$> simpleTableHeader headless)
+ (wrapId <$> simpleTableRow)
+ sep simpleTableFooter
-- Simple tables get 0s for relative column widths (i.e., use default)
case B.toList tbl of
[Table c a _w h l] -> return $ B.singleton $
@@ -1134,7 +1181,8 @@ simpleTable headless = do
gridTable :: PandocMonad m
=> Bool -- ^ Headerless table
-> RSTParser m Blocks
-gridTable headerless = gridTableWith parseBlocks headerless
+gridTable headerless = runIdentity <$>
+ gridTableWith (Identity <$> parseBlocks) headerless
table :: PandocMonad m => RSTParser m Blocks
table = gridTable False <|> simpleTable False <|>
@@ -1161,7 +1209,7 @@ inline = choice [ note -- can start with whitespace, so try before ws
, symbol ] <?> "inline"
parseInlineFromString :: PandocMonad m => String -> RSTParser m Inlines
-parseInlineFromString = parseFromString (trimInlines . mconcat <$> many inline)
+parseInlineFromString = parseFromString' (trimInlines . mconcat <$> many inline)
hyphens :: Monad m => RSTParser m Inlines
hyphens = do
@@ -1220,7 +1268,8 @@ interpretedRole = try $ do
(role, contents) <- roleBefore <|> roleAfter
renderRole contents Nothing role nullAttr
-renderRole :: PandocMonad m => String -> Maybe String -> String -> Attr -> RSTParser m Inlines
+renderRole :: PandocMonad m
+ => String -> Maybe String -> String -> Attr -> RSTParser m Inlines
renderRole contents fmt role attr = case role of
"sup" -> return $ B.superscript $ B.str contents
"superscript" -> return $ B.superscript $ B.str contents
@@ -1353,7 +1402,8 @@ referenceLink = try $ do
(k:_) -> return k
((src,tit), attr) <- lookupKey [] key
-- if anonymous link, remove key so it won't be used again
- when (isAnonKey key) $ updateState $ \s -> s{ stateKeys = M.delete key keyTable }
+ when (isAnonKey key) $ updateState $ \s ->
+ s{ stateKeys = M.delete key keyTable }
return $ B.linkWith attr src tit label'
-- We keep a list of oldkeys so we can detect lookup loops.
@@ -1423,7 +1473,7 @@ note = try $ do
-- Note references inside other notes are allowed in reST, but
-- not yet in this implementation.
updateState $ \st -> st{ stateNotes = [] }
- contents <- parseFromString parseBlocks raw
+ contents <- parseFromString' parseBlocks raw
let newnotes = if (ref == "*" || ref == "#") -- auto-numbered
-- delete the note so the next auto-numbered note
-- doesn't get the same contents:
diff --git a/src/Text/Pandoc/Readers/TWiki.hs b/src/Text/Pandoc/Readers/TWiki.hs
index ecb609ae9..9e544c4ac 100644
--- a/src/Text/Pandoc/Readers/TWiki.hs
+++ b/src/Text/Pandoc/Readers/TWiki.hs
@@ -49,14 +49,17 @@ import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (enclosed, macro, nested)
import Text.Pandoc.Readers.HTML (htmlTag, isCommentTag)
import Text.Pandoc.XML (fromEntities)
+import Data.Text (Text)
+import qualified Data.Text as T
-- | Read twiki from an input string and return a Pandoc document.
readTWiki :: PandocMonad m
=> ReaderOptions
- -> String
+ -> Text
-> m Pandoc
readTWiki opts s = do
- res <- readWithM parseTWiki def{ stateOptions = opts } (s ++ "\n\n")
+ res <- readWithM parseTWiki def{ stateOptions = opts }
+ (T.unpack s ++ "\n\n")
case res of
Left e -> throwError e
Right d -> return d
@@ -106,7 +109,7 @@ parseHtmlContentWithAttrs tag parser = do
parsedContent <- try $ parseContent content
return (attr, parsedContent)
where
- parseContent = parseFromString $ nested $ manyTill parser endOfContent
+ parseContent = parseFromString' $ nested $ manyTill parser endOfContent
endOfContent = try $ skipMany blankline >> skipSpaces >> eof
parseHtmlContent :: PandocMonad m => String -> TWParser m a -> TWParser m [a]
@@ -233,7 +236,7 @@ listItemLine prefix marker = lineContent >>= parseContent >>= return . mconcat
filterSpaces = reverse . dropWhile (== ' ') . reverse
listContinuation = notFollowedBy (string prefix >> marker) >>
string " " >> lineContent
- parseContent = parseFromString $ many1 $ nestedList <|> parseInline
+ parseContent = parseFromString' $ many1 $ nestedList <|> parseInline
parseInline = many1Till inline (lastNewline <|> newlineBeforeNestedList) >>=
return . B.plain . mconcat
nestedList = list prefix
@@ -297,7 +300,7 @@ noautolink = do
setState $ st{ stateAllowLinks = True }
return $ mconcat blocks
where
- parseContent = parseFromString $ many $ block
+ parseContent = parseFromString' $ many $ block
para :: PandocMonad m => TWParser m B.Blocks
para = many1Till inline endOfParaElement >>= return . result . mconcat
@@ -349,13 +352,13 @@ linebreak = newline >> notFollowedBy newline >> (lastNewline <|> innerNewline)
where lastNewline = eof >> return mempty
innerNewline = return B.space
-between :: (Monoid c, PandocMonad m)
+between :: (Monoid c, PandocMonad m, Show b)
=> TWParser m a -> TWParser m b -> (TWParser m b -> TWParser m c)
-> TWParser m c
between start end p =
mconcat <$> try (start >> notFollowedBy whitespace >> many1Till (p end) end)
-enclosed :: (Monoid b, PandocMonad m)
+enclosed :: (Monoid b, PandocMonad m, Show a)
=> TWParser m a -> (TWParser m a -> TWParser m b) -> TWParser m b
enclosed sep p = between sep (try $ sep <* endMarker) p
where
@@ -525,4 +528,4 @@ linkText = do
return (url, "", content)
where
linkContent = (char '[') >> many1Till anyChar (char ']') >>= parseLinkContent
- parseLinkContent = parseFromString $ many1 inline
+ parseLinkContent = parseFromString' $ many1 inline
diff --git a/src/Text/Pandoc/Readers/Textile.hs b/src/Text/Pandoc/Readers/Textile.hs
index 047aa061c..1669e3e51 100644
--- a/src/Text/Pandoc/Readers/Textile.hs
+++ b/src/Text/Pandoc/Readers/Textile.hs
@@ -1,6 +1,6 @@
{-
-Copyright (C) 2010-2015 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
- and John MacFarlane
+Copyright (C) 2010-2012 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
+ 2010-2017 John MacFarlane
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,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Readers.Textile
- Copyright : Copyright (C) 2010-2015 Paul Rivier and John MacFarlane
+ Copyright : Copyright (C) 2010-2012 Paul Rivier
+ 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Paul Rivier <paul*rivier#demotera*com>
@@ -69,14 +70,17 @@ import Text.Pandoc.Parsing
import Text.Pandoc.Readers.HTML (htmlTag, isBlockTag, isInlineTag)
import Text.Pandoc.Readers.LaTeX (rawLaTeXBlock, rawLaTeXInline)
import Text.Pandoc.Shared (trim)
+import Data.Text (Text)
+import qualified Data.Text as T
-- | Parse a Textile text and return a Pandoc document.
readTextile :: PandocMonad m
=> ReaderOptions -- ^ Reader options
- -> String -- ^ String to parse (assuming @'\n'@ line endings)
+ -> Text -- ^ String to parse (assuming @'\n'@ line endings)
-> m Pandoc
readTextile opts s = do
- parsed <- readWithM parseTextile def{ stateOptions = opts } (s ++ "\n\n")
+ parsed <- readWithM parseTextile def{ stateOptions = opts }
+ (T.unpack s ++ "\n\n")
case parsed of
Right result -> return result
Left e -> throwError e
@@ -314,7 +318,7 @@ definitionListItem = try $ do
optional whitespace >> newline
s <- many1Till anyChar (try (string "=:" >> newline))
-- this ++ "\n\n" does not look very good
- ds <- parseFromString parseBlocks (s ++ "\n\n")
+ ds <- parseFromString' parseBlocks (s ++ "\n\n")
return [ds]
-- raw content
@@ -366,7 +370,7 @@ tableCell = try $ do
notFollowedBy blankline
raw <- trim <$>
many (noneOf "|\n" <|> try (char '\n' <* notFollowedBy blankline))
- content <- mconcat <$> parseFromString (many inline) raw
+ content <- mconcat <$> parseFromString' (many inline) raw
return ((isHeader, alignment), B.plain content)
-- | A table row is made of many table cells
@@ -388,7 +392,7 @@ table = try $ do
_ <- attributes
char '.'
rawcapt <- trim <$> anyLine
- parseFromString (mconcat <$> many inline) rawcapt
+ parseFromString' (mconcat <$> many inline) rawcapt
rawrows <- many1 $ (skipMany ignorableRow) >> tableRow
skipMany ignorableRow
blanklines
@@ -506,7 +510,7 @@ note = try $ do
notes <- stateNotes <$> getState
case lookup ref notes of
Nothing -> fail "note not found"
- Just raw -> B.note <$> parseFromString parseBlocks raw
+ Just raw -> B.note <$> parseFromString' parseBlocks raw
-- | Special chars
markupChars :: [Char]
@@ -585,8 +589,9 @@ link = try $ do
char ':'
let stop = if bracketed
then char ']'
- else lookAhead $ space <|>
- try (oneOf "!.,;:" *> (space <|> newline))
+ else lookAhead $ space <|> eof' <|>
+ try (oneOf "!.,;:" *>
+ (space <|> newline <|> eof'))
url <- many1Till nonspaceChar stop
let name' = if B.toList name == [Str "$"] then B.str url else name
return $ if attr == nullAttr
@@ -690,7 +695,7 @@ langAttr = do
return $ \(id',classes,keyvals) -> (id',classes,("lang",lang):keyvals)
-- | Parses material surrounded by a parser.
-surrounded :: PandocMonad m
+surrounded :: (PandocMonad m, Show t)
=> ParserT [Char] st m t -- ^ surrounding parser
-> ParserT [Char] st m a -- ^ content parser (to be used repeatedly)
-> ParserT [Char] st m [a]
@@ -727,3 +732,5 @@ groupedInlineMarkup = try $ do
singleton :: a -> [a]
singleton x = [x]
+eof' :: Monad m => ParserT [Char] s m Char
+eof' = '\n' <$ eof
diff --git a/src/Text/Pandoc/Readers/Txt2Tags.hs b/src/Text/Pandoc/Readers/Txt2Tags.hs
index 33f785109..260bb7fff 100644
--- a/src/Text/Pandoc/Readers/Txt2Tags.hs
+++ b/src/Text/Pandoc/Readers/Txt2Tags.hs
@@ -42,11 +42,11 @@ import Text.Pandoc.Definition
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (macro, space, spaces, uri)
import Text.Pandoc.Shared (compactify, compactifyDL, escapeURI)
---import Network.URI (isURI) -- Not sure whether to use this function
import Control.Monad (guard, void, when)
import Control.Monad.Reader (Reader, asks, runReader)
import Data.Default
-
+import Data.Text (Text)
+import qualified Data.Text as T
import Control.Monad.Except (catchError, throwError)
import Data.Time.Format (formatTime)
import Text.Pandoc.Class (PandocMonad)
@@ -91,11 +91,11 @@ getT2TMeta = do
-- | Read Txt2Tags from an input string returning a Pandoc document
readTxt2Tags :: PandocMonad m
=> ReaderOptions
- -> String
+ -> Text
-> m Pandoc
readTxt2Tags opts s = do
meta <- getT2TMeta
- let parsed = flip runReader meta $ readWithM parseT2T (def {stateOptions = opts}) (s ++ "\n\n")
+ let parsed = flip runReader meta $ readWithM parseT2T (def {stateOptions = opts}) (T.unpack s ++ "\n\n")
case parsed of
Right result -> return $ result
Left e -> throwError e
@@ -213,7 +213,7 @@ quote :: T2T Blocks
quote = try $ do
lookAhead tab
rawQuote <- many1 (tab *> optional spaces *> anyLine)
- contents <- parseFromString parseBlocks (intercalate "\n" rawQuote ++ "\n\n")
+ contents <- parseFromString' parseBlocks (intercalate "\n" rawQuote ++ "\n\n")
return $ B.blockQuote contents
commentLine :: T2T Inlines
@@ -265,7 +265,7 @@ listItem start end = try $ do
firstLine <- anyLineNewline
blank <- option "" ("\n" <$ blankline)
rest <- concat <$> many (listContinuation markerLength)
- parseFromString end $ firstLine ++ blank ++ rest
+ parseFromString' end $ firstLine ++ blank ++ rest
-- continuation of a list item - indented and separated by blankline or endline.
-- Note: nested lists are parsed as continuations.
@@ -277,12 +277,6 @@ listContinuation markerLength = try $
<*> many blankline)
where listLine = try $ indentWith markerLength *> anyLineNewline
-anyLineNewline :: T2T String
-anyLineNewline = (++ "\n") <$> anyLine
-
-indentWith :: Int -> T2T String
-indentWith n = count n space
-
-- Table
table :: T2T Blocks
@@ -446,7 +440,7 @@ inlineMarkup p f c special = try $ do
Just middle -> do
lastChar <- anyChar
end <- many1 (char c)
- let parser inp = parseFromString (mconcat <$> many p) inp
+ let parser inp = parseFromString' (mconcat <$> many p) inp
let start' = case drop 2 start of
"" -> mempty
xs -> special xs
diff --git a/src/Text/Pandoc/SelfContained.hs b/src/Text/Pandoc/SelfContained.hs
index 53cb4a4b5..55df147b6 100644
--- a/src/Text/Pandoc/SelfContained.hs
+++ b/src/Text/Pandoc/SelfContained.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2011-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2011-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2011-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,13 +35,14 @@ import Codec.Compression.GZip as Gzip
import Control.Applicative ((<|>))
import Control.Monad.Except (throwError)
import Control.Monad.Trans (lift)
+import Data.Monoid ((<>))
import Data.ByteString (ByteString)
import Data.ByteString.Base64
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy as L
import Data.Char (isAlphaNum, isAscii, toLower)
import Data.List (isPrefixOf)
-import Network.URI (URI (..), escapeURIString, isURI, parseURI)
+import Network.URI (URI (..), escapeURIString, parseURI)
import System.FilePath (takeDirectory, takeExtension, (</>))
import Text.HTML.TagSoup
import Text.Pandoc.Class (PandocMonad (..), fetchItem, report)
@@ -49,7 +50,7 @@ import Text.Pandoc.Error
import Text.Pandoc.Logging
import Text.Pandoc.MIME (MimeType)
import Text.Pandoc.Options (WriterOptions (..))
-import Text.Pandoc.Shared (renderTags', trim)
+import Text.Pandoc.Shared (isURI, renderTags', trim)
import Text.Pandoc.UTF8 (toString)
import Text.Parsec (ParsecT, runParserT)
import qualified Text.Parsec as P
@@ -95,9 +96,9 @@ convertTags sourceURL (t@(TagOpen "script" as):TagClose "script":ts) =
(("src",dataUri) : [(x,y) | (x,y) <- as, x /= "src"]) :
TagClose "script" : rest
Right (mime, bs)
- | (mime == "text/javascript" ||
- mime == "application/javascript" ||
- mime == "application/x-javascript") &&
+ | ("text/javascript" `isPrefixOf` mime ||
+ "application/javascript" `isPrefixOf` mime ||
+ "application/x-javascript" `isPrefixOf` mime) &&
not ("</script" `B.isInfixOf` bs) ->
return $
TagOpen "script" [("type", typeAttr)|not (null typeAttr)]
@@ -121,11 +122,12 @@ convertTags sourceURL (t@(TagOpen "link" as):ts) =
(("href",dataUri) : [(x,y) | (x,y) <- as, x /= "href"]) :
rest
Right (mime, bs)
- | mime == "text/css" && not ("</" `B.isInfixOf` bs) -> do
+ | "text/css" `isPrefixOf` mime
+ && not ("</" `B.isInfixOf` bs) -> do
rest <- convertTags sourceURL $
dropWhile (==TagClose "link") ts
return $
- TagOpen "style" [("type", "text/css")]
+ TagOpen "style" [("type", mime)]
: TagText (toString bs)
: TagClose "style"
: rest
@@ -149,7 +151,21 @@ cssURLs sourceURL d orig = do
parseCSSUrls :: PandocMonad m
=> Maybe String -> FilePath -> ParsecT ByteString () m ByteString
parseCSSUrls sourceURL d = B.concat <$> P.many
- (pCSSWhite <|> pCSSComment <|> pCSSUrl sourceURL d <|> pCSSOther)
+ (pCSSWhite <|> pCSSComment <|> pCSSImport sourceURL d <|>
+ pCSSUrl sourceURL d <|> pCSSOther)
+
+pCSSImport :: PandocMonad m => Maybe String -> FilePath
+ -> ParsecT ByteString () m ByteString
+pCSSImport sourceURL d = P.try $ do
+ P.string "@import"
+ P.spaces
+ res <- (pQuoted <|> pUrl) >>= handleCSSUrl sourceURL d
+ P.spaces
+ P.char ';'
+ P.spaces
+ case res of
+ Left b -> return $ B.pack "@import " <> b
+ Right (_, b) -> return b
-- Note: some whitespace in CSS is significant, so we can't collapse it!
pCSSWhite :: PandocMonad m => ParsecT ByteString () m ByteString
@@ -170,6 +186,24 @@ pCSSOther = do
pCSSUrl :: PandocMonad m
=> Maybe String -> FilePath -> ParsecT ByteString () m ByteString
pCSSUrl sourceURL d = P.try $ do
+ res <- pUrl >>= handleCSSUrl sourceURL d
+ case res of
+ Left b -> return b
+ Right (mt,b) -> do
+ let enc = makeDataURI (mt, b)
+ return (B.pack $ "url(" ++ enc ++ ")")
+
+pQuoted :: PandocMonad m
+ => ParsecT ByteString () m (String, ByteString)
+pQuoted = P.try $ do
+ quote <- P.oneOf "\"'"
+ url <- P.manyTill P.anyChar (P.char quote)
+ let fallback = B.pack ([quote] ++ trim url ++ [quote])
+ return (url, fallback)
+
+pUrl :: PandocMonad m
+ => ParsecT ByteString () m (String, ByteString)
+pUrl = P.try $ do
P.string "url("
P.spaces
quote <- P.option Nothing (Just <$> P.oneOf "\"'")
@@ -178,12 +212,29 @@ pCSSUrl sourceURL d = P.try $ do
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
+ return (url, fallback)
+
+handleCSSUrl :: PandocMonad m
+ => Maybe String -> FilePath -> (String, ByteString)
+ -> ParsecT ByteString () m
+ (Either ByteString (MimeType, ByteString))
+handleCSSUrl sourceURL d (url, fallback) = do
+ -- pipes are used in URLs provided by Google Code fonts
+ -- but parseURI doesn't like them, so we escape them:
+ case escapeURIString (/='|') (trim url) of
+ '#':_ -> return $ Left fallback
+ 'd':'a':'t':'a':':':_ -> return $ Left fallback
u -> do let url' = if isURI u then u else d </> u
- enc <- lift $ getDataURI sourceURL "" url'
- return (B.pack $ "url(" ++ enc ++ ")")
+ res <- lift $ getData sourceURL "" url'
+ case res of
+ Left uri -> return $ Left (B.pack $ "url(" ++ uri ++ ")")
+ Right (mt, raw) -> do
+ -- note that the downloaded CSS may
+ -- itself contain url(...).
+ b <- if "text/css" `isPrefixOf` mt
+ then cssURLs sourceURL d raw
+ else return raw
+ return $ Right (mt, b)
getDataURI :: PandocMonad m => Maybe String -> MimeType -> String -> m String
getDataURI sourceURL mimetype src = do
@@ -215,7 +266,7 @@ getData sourceURL mimetype src = do
uriQuery = "",
uriFragment = "" }
_ -> Nothing
- result <- if mime == "text/css"
+ result <- if "text/css" `isPrefixOf` mime
then cssURLs cssSourceURL (takeDirectory src) raw'
else return raw'
return $ Right (mime, result)
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index 8256d14c0..745e809d0 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -2,7 +2,7 @@
FlexibleContexts, ScopedTypeVariables, PatternGuards,
ViewPatterns #-}
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -70,6 +70,7 @@ module Text.Pandoc.Shared (
isTightList,
addMetaField,
makeMeta,
+ eastAsianLineBreakFilter,
-- * TagSoup HTML handling
renderTags',
-- * File handling
@@ -81,6 +82,9 @@ module Text.Pandoc.Shared (
openURL,
collapseFilePath,
filteredFilesFromArchive,
+ -- * URI handling
+ schemes,
+ isURI,
-- * Error handling
mapLeft,
-- * for squashing blocks
@@ -104,7 +108,7 @@ import Data.List ( find, stripPrefix, intercalate )
import Data.Maybe (mapMaybe)
import Data.Version ( showVersion )
import qualified Data.Map as M
-import Network.URI ( escapeURIString, unEscapeString )
+import Network.URI ( URI(uriScheme), escapeURIString, unEscapeString, parseURI )
import qualified Data.Set as Set
import System.Directory
import System.FilePath (splitDirectories, isPathSeparator)
@@ -117,6 +121,7 @@ import qualified Control.Monad.State as S
import qualified Control.Exception as E
import Control.Monad (msum, unless, MonadPlus(..))
import Text.Pandoc.Pretty (charWidth)
+import Text.Pandoc.Generic (bottomUp)
import Text.Pandoc.Compat.Time
import Data.Time.Clock.POSIX
import System.IO.Error
@@ -128,7 +133,7 @@ import qualified Data.ByteString as BS
import qualified Data.ByteString.Char8 as B8
import Data.ByteString.Base64 (decodeLenient)
import Data.Sequence (ViewR(..), ViewL(..), viewl, viewr)
-import qualified Data.Text as T (toUpper, pack, unpack)
+import qualified Data.Text as T
import Data.ByteString.Lazy (toChunks, fromChunks)
import qualified Data.ByteString.Lazy as BL
import Paths_pandoc (version)
@@ -140,9 +145,9 @@ import Text.Pandoc.Data (dataFiles)
#else
import Paths_pandoc (getDataFileName)
#endif
-#ifdef HTTP_CLIENT
import Network.HTTP.Client (httpLbs, responseBody, responseHeaders,
- Request(port,host,requestHeaders))
+ Request(port,host,requestHeaders),
+ HttpException)
import Network.HTTP.Client (parseRequest)
import Network.HTTP.Client (newManager)
import Network.HTTP.Client.Internal (addProxy)
@@ -150,12 +155,6 @@ import Network.HTTP.Client.TLS (tlsManagerSettings)
import System.Environment (getEnv)
import Network.HTTP.Types.Header ( hContentType, hUserAgent)
import Network (withSocketsDo)
-#else
-import Network.URI (parseURI)
-import Network.HTTP (findHeader, rspBody,
- RequestMethod(..), HeaderName(..), mkRequest)
-import Network.Browser (browse, setAllowRedirects, setOutHandler, request)
-#endif
-- | Version number of pandoc library.
pandocVersion :: String
@@ -280,26 +279,20 @@ escapeURI = escapeURIString (not . needsEscaping)
where needsEscaping c = isSpace c || c `elem`
['<','>','|','"','{','}','[',']','^', '`']
-
-- | Convert tabs to spaces and filter out DOS line endings.
-- Tabs will be preserved if tab stop is set to 0.
tabFilter :: Int -- ^ Tab stop
- -> String -- ^ Input
- -> String
-tabFilter tabStop =
- let go _ [] = ""
- go _ ('\n':xs) = '\n' : go tabStop xs
- go _ ('\r':'\n':xs) = '\n' : go tabStop xs
- go _ ('\r':xs) = '\n' : go tabStop xs
- go spsToNextStop ('\t':xs) =
- if tabStop == 0
- then '\t' : go tabStop xs
- else replicate spsToNextStop ' ' ++ go tabStop xs
- go 1 (x:xs) =
- x : go tabStop xs
- go spsToNextStop (x:xs) =
- x : go (spsToNextStop - 1) xs
- in go tabStop
+ -> T.Text -- ^ Input
+ -> T.Text
+tabFilter tabStop = T.filter (/= '\r') . T.unlines .
+ (if tabStop == 0 then id else map go) . T.lines
+ where go s =
+ let (s1, s2) = T.break (== '\t') s
+ in if T.null s2
+ then s1
+ else s1 <> T.replicate
+ (tabStop - (T.length s1 `mod` tabStop)) (T.pack " ")
+ <> go (T.drop 1 s2)
--
-- Date/time
@@ -581,6 +574,16 @@ makeMeta title authors date =
$ addMetaField "date" (B.fromList date)
$ nullMeta
+-- | Remove soft breaks between East Asian characters.
+eastAsianLineBreakFilter :: Pandoc -> Pandoc
+eastAsianLineBreakFilter = bottomUp go
+ where go (x:SoftBreak:y:zs) =
+ case (stringify x, stringify y) of
+ (xs@(_:_), (c:_))
+ | charWidth (last xs) == 2 && charWidth c == 2 -> x:y:zs
+ _ -> x:SoftBreak:y:zs
+ go xs = xs
+
--
-- TagSoup HTML handling
--
@@ -709,14 +712,13 @@ readDataFileUTF8 userDir fname =
UTF8.toString `fmap` readDataFile userDir fname
-- | Read from a URL and return raw data and maybe mime type.
-openURL :: String -> IO (BS.ByteString, Maybe MimeType)
+openURL :: String -> IO (Either HttpException (BS.ByteString, Maybe MimeType))
openURL u
| Just u'' <- stripPrefix "data:" u =
let mime = takeWhile (/=',') u''
contents = B8.pack $ unEscapeString $ drop 1 $ dropWhile (/=',') u''
- in return (decodeLenient contents, Just mime)
-#ifdef HTTP_CLIENT
- | otherwise = withSocketsDo $ do
+ in return $ Right (decodeLenient contents, Just mime)
+ | otherwise = E.try $ withSocketsDo $ do
let parseReq = parseRequest
(proxy :: Either IOError String) <-
tryIOError $ getEnv "http_proxy"
@@ -738,19 +740,6 @@ openURL u
resp <- newManager tlsManagerSettings >>= httpLbs req''
return (BS.concat $ toChunks $ responseBody resp,
UTF8.toString `fmap` lookup hContentType (responseHeaders resp))
-#else
- | otherwise = getBodyAndMimeType `fmap` browse
- (do liftIO $ UTF8.hPutStrLn stderr $ "Fetching " ++ u ++ "..."
- setOutHandler $ const (return ())
- setAllowRedirects True
- request (getRequest' u'))
- where getBodyAndMimeType (_, r) = (rspBody r, findHeader HdrContentType r)
- getRequest' uriString = case parseURI uriString of
- Nothing -> error ("Not a valid URL: " ++
- uriString)
- Just v -> mkRequest GET v
- u' = escapeURIString (/= '|') u -- pipes are rejected by Network.URI
-#endif
--
-- Error reporting
@@ -794,6 +783,71 @@ filteredFilesFromArchive zf f =
fileAndBinary :: Archive -> FilePath -> Maybe (FilePath, BL.ByteString)
fileAndBinary a fp = findEntryByPath fp a >>= \e -> Just (fp, fromEntry e)
+
+--
+-- IANA URIs
+--
+
+-- | Schemes from http://www.iana.org/assignments/uri-schemes.html plus
+-- the unofficial schemes doi, javascript, isbn, pmid.
+schemes :: Set.Set String
+schemes = Set.fromList
+ -- Official IANA schemes
+ [ "aaa", "aaas", "about", "acap", "acct", "acr", "adiumxtra", "afp", "afs"
+ , "aim", "appdata", "apt", "attachment", "aw", "barion", "beshare", "bitcoin"
+ , "blob", "bolo", "browserext", "callto", "cap", "chrome", "chrome-extension"
+ , "cid", "coap", "coaps", "com-eventbrite-attendee", "content", "crid", "cvs"
+ , "data", "dav", "dict", "dis", "dlna-playcontainer", "dlna-playsingle"
+ , "dns", "dntp", "dtn", "dvb", "ed2k", "example", "facetime", "fax", "feed"
+ , "feedready", "file", "filesystem", "finger", "fish", "ftp", "geo", "gg"
+ , "git", "gizmoproject", "go", "gopher", "graph", "gtalk", "h323", "ham"
+ , "hcp", "http", "https", "hxxp", "hxxps", "hydrazone", "iax", "icap", "icon"
+ , "im", "imap", "info", "iotdisco", "ipn", "ipp", "ipps", "irc", "irc6"
+ , "ircs", "iris", "iris.beep", "iris.lwz", "iris.xpc", "iris.xpcs"
+ , "isostore", "itms", "jabber", "jar", "jms", "keyparc", "lastfm", "ldap"
+ , "ldaps", "lvlt", "magnet", "mailserver", "mailto", "maps", "market"
+ , "message", "mid", "mms", "modem", "mongodb", "moz", "ms-access"
+ , "ms-browser-extension", "ms-drive-to", "ms-enrollment", "ms-excel"
+ , "ms-gamebarservices", "ms-getoffice", "ms-help", "ms-infopath"
+ , "ms-media-stream-id", "ms-officeapp", "ms-project", "ms-powerpoint"
+ , "ms-publisher", "ms-search-repair", "ms-secondary-screen-controller"
+ , "ms-secondary-screen-setup", "ms-settings", "ms-settings-airplanemode"
+ , "ms-settings-bluetooth", "ms-settings-camera", "ms-settings-cellular"
+ , "ms-settings-cloudstorage", "ms-settings-connectabledevices"
+ , "ms-settings-displays-topology", "ms-settings-emailandaccounts"
+ , "ms-settings-language", "ms-settings-location", "ms-settings-lock"
+ , "ms-settings-nfctransactions", "ms-settings-notifications"
+ , "ms-settings-power", "ms-settings-privacy", "ms-settings-proximity"
+ , "ms-settings-screenrotation", "ms-settings-wifi", "ms-settings-workplace"
+ , "ms-spd", "ms-sttoverlay", "ms-transit-to", "ms-virtualtouchpad"
+ , "ms-visio", "ms-walk-to", "ms-whiteboard", "ms-whiteboard-cmd", "ms-word"
+ , "msnim", "msrp", "msrps", "mtqp", "mumble", "mupdate", "mvn", "news", "nfs"
+ , "ni", "nih", "nntp", "notes", "ocf", "oid", "onenote", "onenote-cmd"
+ , "opaquelocktoken", "pack", "palm", "paparazzi", "pkcs11", "platform", "pop"
+ , "pres", "prospero", "proxy", "pwid", "psyc", "qb", "query", "redis"
+ , "rediss", "reload", "res", "resource", "rmi", "rsync", "rtmfp", "rtmp"
+ , "rtsp", "rtsps", "rtspu", "secondlife", "service", "session", "sftp", "sgn"
+ , "shttp", "sieve", "sip", "sips", "skype", "smb", "sms", "smtp", "snews"
+ , "snmp", "soap.beep", "soap.beeps", "soldat", "spotify", "ssh", "steam"
+ , "stun", "stuns", "submit", "svn", "tag", "teamspeak", "tel", "teliaeid"
+ , "telnet", "tftp", "things", "thismessage", "tip", "tn3270", "tool", "turn"
+ , "turns", "tv", "udp", "unreal", "urn", "ut2004", "v-event", "vemmi"
+ , "ventrilo", "videotex", "vnc", "view-source", "wais", "webcal", "wpid"
+ , "ws", "wss", "wtai", "wyciwyg", "xcon", "xcon-userid", "xfire"
+ , "xmlrpc.beep", "xmlrpc.beeps", "xmpp", "xri", "ymsgr", "z39.50", "z39.50r"
+ , "z39.50s"
+ -- Inofficial schemes
+ , "doi", "isbn", "javascript", "pmid"
+ ]
+
+-- | Check if the string is a valid URL with a IANA or frequently used but
+-- unofficial scheme (see @schemes@).
+isURI :: String -> Bool
+isURI = maybe False hasKnownScheme . parseURI
+ where
+ hasKnownScheme = (`Set.member` schemes) . map toLower .
+ filter (/= ':') . uriScheme
+
---
--- Squash blocks into inlines
---
diff --git a/src/Text/Pandoc/Slides.hs b/src/Text/Pandoc/Slides.hs
index b53e0eb6d..cd7695dbe 100644
--- a/src/Text/Pandoc/Slides.hs
+++ b/src/Text/Pandoc/Slides.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2012-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 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 26aeb9a73..9b635a97b 100644
--- a/src/Text/Pandoc/Templates.hs
+++ b/src/Text/Pandoc/Templates.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-
-Copyright (C) 2009-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2009-2017 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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Templates
- Copyright : Copyright (C) 2009-2016 John MacFarlane
+ Copyright : Copyright (C) 2009-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/UTF8.hs b/src/Text/Pandoc/UTF8.hs
index d88a44948..663f30d92 100644
--- a/src/Text/Pandoc/UTF8.hs
+++ b/src/Text/Pandoc/UTF8.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2017 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.UTF8
- Copyright : Copyright (C) 2010-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -28,16 +29,25 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
UTF-8 aware string IO functions that will work with GHC 6.10, 6.12, or 7.
-}
module Text.Pandoc.UTF8 ( readFile
- , writeFile
, getContents
+ , writeFileWith
+ , writeFile
+ , putStrWith
, putStr
+ , putStrLnWith
, putStrLn
+ , hPutStrWith
, hPutStr
+ , hPutStrLnWith
, hPutStrLn
, hGetContents
, toString
+ , toText
, fromString
+ , fromText
, toStringLazy
+ , fromTextLazy
+ , toTextLazy
, fromStringLazy
, encodePath
, decodeArg
@@ -46,7 +56,7 @@ module Text.Pandoc.UTF8 ( readFile
where
import qualified Data.ByteString.Char8 as B
-import qualified Data.ByteString.Lazy as BL
+import qualified Data.ByteString.Lazy.Char8 as BL
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as TL
@@ -61,23 +71,43 @@ readFile f = do
h <- openFile (encodePath f) ReadMode
hGetContents h
-writeFile :: FilePath -> String -> IO ()
-writeFile f s = withFile (encodePath f) WriteMode $ \h -> hPutStr h s
-
getContents :: IO String
getContents = hGetContents stdin
+writeFileWith :: Newline -> FilePath -> String -> IO ()
+writeFileWith eol f s =
+ withFile (encodePath f) WriteMode $ \h -> hPutStrWith eol h s
+
+writeFile :: FilePath -> String -> IO ()
+writeFile = writeFileWith nativeNewline
+
+putStrWith :: Newline -> String -> IO ()
+putStrWith eol s = hPutStrWith eol stdout s
+
putStr :: String -> IO ()
-putStr s = hPutStr stdout s
+putStr = putStrWith nativeNewline
+
+putStrLnWith :: Newline -> String -> IO ()
+putStrLnWith eol s = hPutStrLnWith eol stdout s
putStrLn :: String -> IO ()
-putStrLn s = hPutStrLn stdout s
+putStrLn = putStrLnWith nativeNewline
+
+hPutStrWith :: Newline -> Handle -> String -> IO ()
+hPutStrWith eol h s =
+ hSetNewlineMode h (NewlineMode eol eol) >>
+ hSetEncoding h utf8 >> IO.hPutStr h s
hPutStr :: Handle -> String -> IO ()
-hPutStr h s = hSetEncoding h utf8 >> IO.hPutStr h s
+hPutStr = hPutStrWith nativeNewline
+
+hPutStrLnWith :: Newline -> Handle -> String -> IO ()
+hPutStrLnWith eol h s =
+ hSetNewlineMode h (NewlineMode eol eol) >>
+ hSetEncoding h utf8 >> IO.hPutStrLn h s
hPutStrLn :: Handle -> String -> IO ()
-hPutStrLn h s = hSetEncoding h utf8 >> IO.hPutStrLn h s
+hPutStrLn = hPutStrLnWith nativeNewline
hGetContents :: Handle -> IO String
hGetContents = fmap toString . B.hGetContents
@@ -85,34 +115,47 @@ hGetContents = fmap toString . B.hGetContents
-- >> hSetNewlineMode h universalNewlineMode
-- >> IO.hGetContents h
--- | Drop BOM (byte order marker) if present at beginning of string.
--- Note that Data.Text converts the BOM to code point FEFF, zero-width
--- no-break space, so if the string begins with this we strip it off.
-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 Text, also
+-- removing '\r' characters.
+toText :: B.ByteString -> T.Text
+toText = T.decodeUtf8 . filterCRs . dropBOM
+ where dropBOM bs =
+ if "\xEF\xBB\xBF" `B.isPrefixOf` bs
+ then B.drop 3 bs
+ else bs
+ filterCRs = B.filter (/='\r')
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toString :: B.ByteString -> String
-toString = filterCRs . dropBOM . T.unpack . T.decodeUtf8
+toString = T.unpack . toText
-fromString :: String -> B.ByteString
-fromString = T.encodeUtf8 . T.pack
+-- | Convert UTF8-encoded ByteString to Text, also
+-- removing '\r' characters.
+toTextLazy :: BL.ByteString -> TL.Text
+toTextLazy = TL.decodeUtf8 . filterCRs . dropBOM
+ where dropBOM bs =
+ if "\xEF\xBB\xBF" `BL.isPrefixOf` bs
+ then BL.drop 3 bs
+ else bs
+ filterCRs = BL.filter (/='\r')
-- | Convert UTF8-encoded ByteString to String, also
-- removing '\r' characters.
toStringLazy :: BL.ByteString -> String
-toStringLazy = filterCRs . dropBOM . TL.unpack . TL.decodeUtf8
+toStringLazy = TL.unpack . toTextLazy
+
+fromText :: T.Text -> B.ByteString
+fromText = T.encodeUtf8
+
+fromTextLazy :: TL.Text -> BL.ByteString
+fromTextLazy = TL.encodeUtf8
+
+fromString :: String -> B.ByteString
+fromString = fromText . T.pack
fromStringLazy :: String -> BL.ByteString
-fromStringLazy = TL.encodeUtf8 . TL.pack
+fromStringLazy = fromTextLazy . TL.pack
encodePath :: FilePath -> FilePath
encodePath = id
diff --git a/src/Text/Pandoc/UUID.hs b/src/Text/Pandoc/UUID.hs
index 9446c4692..989dd20c6 100644
--- a/src/Text/Pandoc/UUID.hs
+++ b/src/Text/Pandoc/UUID.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
diff --git a/src/Text/Pandoc/Writers.hs b/src/Text/Pandoc/Writers.hs
index 0181f41c9..dbe55449f 100644
--- a/src/Text/Pandoc/Writers.hs
+++ b/src/Text/Pandoc/Writers.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
- Copyright : Copyright (C) 2006-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -83,6 +83,7 @@ module Text.Pandoc.Writers
import Data.Aeson
import Data.List (intercalate)
+import Data.Text (Text)
import Text.Pandoc.Class
import Text.Pandoc.Definition
import Text.Pandoc.Options
@@ -120,59 +121,59 @@ import Text.Parsec.Error
import qualified Text.Pandoc.UTF8 as UTF8
import qualified Data.ByteString.Lazy as BL
-data Writer m = StringWriter (WriterOptions -> Pandoc -> m String)
+data Writer m = TextWriter (WriterOptions -> Pandoc -> m Text)
| ByteStringWriter (WriterOptions -> Pandoc -> m BL.ByteString)
-- | Association list of formats and writers.
writers :: PandocMonad m => [ ( String, Writer m) ]
writers = [
- ("native" , StringWriter writeNative)
- ,("json" , StringWriter $ \o d -> return $ writeJSON o d)
+ ("native" , TextWriter writeNative)
+ ,("json" , TextWriter $ \o d -> return $ writeJSON o d)
,("docx" , ByteStringWriter writeDocx)
,("odt" , ByteStringWriter writeODT)
,("epub" , ByteStringWriter writeEPUB3)
,("epub2" , ByteStringWriter writeEPUB2)
,("epub3" , ByteStringWriter writeEPUB3)
- ,("fb2" , StringWriter writeFB2)
- ,("html" , StringWriter writeHtml5String)
- ,("html4" , StringWriter writeHtml4String)
- ,("html5" , StringWriter writeHtml5String)
- ,("icml" , StringWriter writeICML)
- ,("s5" , StringWriter writeS5)
- ,("slidy" , StringWriter writeSlidy)
- ,("slideous" , StringWriter writeSlideous)
- ,("dzslides" , StringWriter writeDZSlides)
- ,("revealjs" , StringWriter writeRevealJs)
- ,("docbook" , StringWriter writeDocbook5)
- ,("docbook4" , StringWriter writeDocbook4)
- ,("docbook5" , StringWriter writeDocbook5)
- ,("jats" , StringWriter writeJATS)
- ,("opml" , StringWriter writeOPML)
- ,("opendocument" , StringWriter writeOpenDocument)
- ,("latex" , StringWriter writeLaTeX)
- ,("beamer" , StringWriter writeBeamer)
- ,("context" , StringWriter writeConTeXt)
- ,("texinfo" , StringWriter writeTexinfo)
- ,("man" , StringWriter writeMan)
- ,("ms" , StringWriter writeMs)
- ,("markdown" , StringWriter writeMarkdown)
- ,("markdown_strict" , StringWriter writeMarkdown)
- ,("markdown_phpextra" , StringWriter writeMarkdown)
- ,("markdown_github" , StringWriter writeMarkdown)
- ,("markdown_mmd" , StringWriter writeMarkdown)
- ,("plain" , StringWriter writePlain)
- ,("rst" , StringWriter writeRST)
- ,("mediawiki" , StringWriter writeMediaWiki)
- ,("dokuwiki" , StringWriter writeDokuWiki)
- ,("zimwiki" , StringWriter writeZimWiki)
- ,("textile" , StringWriter writeTextile)
- ,("rtf" , StringWriter writeRTF)
- ,("org" , StringWriter writeOrg)
- ,("asciidoc" , StringWriter writeAsciiDoc)
- ,("haddock" , StringWriter writeHaddock)
- ,("commonmark" , StringWriter writeCommonMark)
- ,("tei" , StringWriter writeTEI)
- ,("muse" , StringWriter writeMuse)
+ ,("fb2" , TextWriter writeFB2)
+ ,("html" , TextWriter writeHtml5String)
+ ,("html4" , TextWriter writeHtml4String)
+ ,("html5" , TextWriter writeHtml5String)
+ ,("icml" , TextWriter writeICML)
+ ,("s5" , TextWriter writeS5)
+ ,("slidy" , TextWriter writeSlidy)
+ ,("slideous" , TextWriter writeSlideous)
+ ,("dzslides" , TextWriter writeDZSlides)
+ ,("revealjs" , TextWriter writeRevealJs)
+ ,("docbook" , TextWriter writeDocbook5)
+ ,("docbook4" , TextWriter writeDocbook4)
+ ,("docbook5" , TextWriter writeDocbook5)
+ ,("jats" , TextWriter writeJATS)
+ ,("opml" , TextWriter writeOPML)
+ ,("opendocument" , TextWriter writeOpenDocument)
+ ,("latex" , TextWriter writeLaTeX)
+ ,("beamer" , TextWriter writeBeamer)
+ ,("context" , TextWriter writeConTeXt)
+ ,("texinfo" , TextWriter writeTexinfo)
+ ,("man" , TextWriter writeMan)
+ ,("ms" , TextWriter writeMs)
+ ,("markdown" , TextWriter writeMarkdown)
+ ,("markdown_strict" , TextWriter writeMarkdown)
+ ,("markdown_phpextra" , TextWriter writeMarkdown)
+ ,("markdown_github" , TextWriter writeMarkdown)
+ ,("markdown_mmd" , TextWriter writeMarkdown)
+ ,("plain" , TextWriter writePlain)
+ ,("rst" , TextWriter writeRST)
+ ,("mediawiki" , TextWriter writeMediaWiki)
+ ,("dokuwiki" , TextWriter writeDokuWiki)
+ ,("zimwiki" , TextWriter writeZimWiki)
+ ,("textile" , TextWriter writeTextile)
+ ,("rtf" , TextWriter writeRTF)
+ ,("org" , TextWriter writeOrg)
+ ,("asciidoc" , TextWriter writeAsciiDoc)
+ ,("haddock" , TextWriter writeHaddock)
+ ,("commonmark" , TextWriter writeCommonMark)
+ ,("tei" , TextWriter writeTEI)
+ ,("muse" , TextWriter writeMuse)
]
getWriter :: PandocMonad m => String -> Either String (Writer m)
@@ -182,12 +183,12 @@ getWriter s
Right (writerName, setExts) ->
case lookup writerName writers of
Nothing -> Left $ "Unknown writer: " ++ writerName
- Just (StringWriter r) -> Right $ StringWriter $
+ Just (TextWriter r) -> Right $ TextWriter $
\o -> r o{ writerExtensions = setExts $
getDefaultExtensions writerName }
Just (ByteStringWriter r) -> Right $ ByteStringWriter $
\o -> r o{ writerExtensions = setExts $
getDefaultExtensions writerName }
-writeJSON :: WriterOptions -> Pandoc -> String
-writeJSON _ = UTF8.toStringLazy . encode
+writeJSON :: WriterOptions -> Pandoc -> Text
+writeJSON _ = UTF8.toText . BL.toStrict . encode
diff --git a/src/Text/Pandoc/Writers/AsciiDoc.hs b/src/Text/Pandoc/Writers/AsciiDoc.hs
index 20fa7c209..46dbe6eaf 100644
--- a/src/Text/Pandoc/Writers/AsciiDoc.hs
+++ b/src/Text/Pandoc/Writers/AsciiDoc.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -43,6 +43,7 @@ import Data.Char (isPunctuation, isSpace)
import Data.List (intercalate, intersperse, stripPrefix)
import qualified Data.Map as M
import Data.Maybe (fromMaybe)
+import Data.Text (Text)
import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
@@ -62,7 +63,7 @@ data WriterState = WriterState { defListMarker :: String
}
-- | Convert Pandoc to AsciiDoc.
-writeAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeAsciiDoc opts document =
evalStateT (pandocToAsciiDoc opts document) WriterState{
defListMarker = "::"
@@ -74,16 +75,18 @@ writeAsciiDoc opts document =
type ADW = StateT WriterState
-- | Return asciidoc representation of document.
-pandocToAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> ADW m String
+pandocToAsciiDoc :: PandocMonad m => WriterOptions -> Pandoc -> ADW m Text
pandocToAsciiDoc opts (Pandoc meta blocks) = do
let titleblock = not $ null (docTitle meta) && null (docAuthors meta) &&
null (docDate meta)
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToAsciiDoc opts)
- (fmap (render colwidth) . inlineListToAsciiDoc opts)
+ (fmap render' . blockListToAsciiDoc opts)
+ (fmap render' . inlineListToAsciiDoc opts)
meta
let addTitleLine (String t) = String $
t <> "\n" <> T.replicate (T.length t) "="
diff --git a/src/Text/Pandoc/Writers/CommonMark.hs b/src/Text/Pandoc/Writers/CommonMark.hs
index 5e0a06bf0..ed316ced9 100644
--- a/src/Text/Pandoc/Writers/CommonMark.hs
+++ b/src/Text/Pandoc/Writers/CommonMark.hs
@@ -34,6 +34,7 @@ module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
import CMark
import Control.Monad.State (State, get, modify, runState)
import Data.Foldable (foldrM)
+import Data.Text (Text)
import qualified Data.Text as T
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
@@ -45,7 +46,7 @@ import Text.Pandoc.Writers.HTML (writeHtml5String)
import Text.Pandoc.Writers.Shared
-- | Convert Pandoc to CommonMark.
-writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeCommonMark :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeCommonMark opts (Pandoc meta blocks) = do
let (blocks', notes) = runState (walkM processNotes blocks) []
notes' = if null notes
@@ -71,7 +72,7 @@ processNotes x = return x
node :: NodeType -> [Node] -> Node
node = Node Nothing
-blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m String
+blocksToCommonMark :: PandocMonad m => WriterOptions -> [Block] -> m Text
blocksToCommonMark opts bs = do
let cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
colwidth = if writerWrapText opts == WrapAuto
@@ -79,14 +80,12 @@ blocksToCommonMark opts bs = do
else Nothing
nodes <- blocksToNodes bs
return $
- T.unpack $
nodeToCommonmark cmarkOpts colwidth $
node DOCUMENT nodes
-inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m String
+inlinesToCommonMark :: PandocMonad m => WriterOptions -> [Inline] -> m Text
inlinesToCommonMark opts ils = return $
- T.unpack $ nodeToCommonmark cmarkOpts colwidth
- $ node PARAGRAPH (inlinesToNodes ils)
+ nodeToCommonmark cmarkOpts colwidth $ node PARAGRAPH (inlinesToNodes ils)
where cmarkOpts = [optHardBreaks | isEnabled Ext_hard_line_breaks opts]
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
@@ -139,7 +138,7 @@ blockToNodes (DefinitionList items) ns = blockToNodes (BulletList items') ns
Para term : concat xs
blockToNodes t@(Table _ _ _ _ _) ns = do
s <- writeHtml5String def $! Pandoc nullMeta [t]
- return (node (HTML_BLOCK (T.pack $! s)) [] : ns)
+ return (node (HTML_BLOCK s) [] : ns)
blockToNodes Null ns = return ns
inlinesToNodes :: [Inline] -> [Node]
diff --git a/src/Text/Pandoc/Writers/ConTeXt.hs b/src/Text/Pandoc/Writers/ConTeXt.hs
index 57f920259..2da6a7f9a 100644
--- a/src/Text/Pandoc/Writers/ConTeXt.hs
+++ b/src/Text/Pandoc/Writers/ConTeXt.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2007-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,7 +33,8 @@ import Control.Monad.State
import Data.Char (ord)
import Data.List (intercalate, intersperse)
import Data.Maybe (catMaybes)
-import Network.URI (isURI, unEscapeString)
+import Data.Text (Text)
+import Network.URI (unEscapeString)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
import Text.Pandoc.Definition
@@ -56,7 +57,7 @@ orderedListStyles :: [Char]
orderedListStyles = cycle "narg"
-- | Convert Pandoc to ConTeXt.
-writeConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeConTeXt options document =
let defaultWriterState = WriterState { stNextRef = 1
, stOrderedListLevel = 0
@@ -66,17 +67,19 @@ writeConTeXt options document =
type WM = StateT WriterState
-pandocToConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> WM m String
+pandocToConTeXt :: PandocMonad m => WriterOptions -> Pandoc -> WM m Text
pandocToConTeXt options (Pandoc meta blocks) = do
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToConTeXt)
- (fmap (render colwidth) . inlineListToConTeXt)
+ (fmap render' . blockListToConTeXt)
+ (fmap render' . inlineListToConTeXt)
meta
body <- mapM (elementToConTeXt options) $ hierarchicalize blocks
- let main = (render colwidth . vcat) body
+ let main = (render' . vcat) body
let layoutFromMargins = intercalate [','] $ catMaybes $
map (\(x,y) ->
((x ++ "=") ++) <$> getField y metadata)
diff --git a/src/Text/Pandoc/Writers/Custom.hs b/src/Text/Pandoc/Writers/Custom.hs
index ce90e4834..1314ef844 100644
--- a/src/Text/Pandoc/Writers/Custom.hs
+++ b/src/Text/Pandoc/Writers/Custom.hs
@@ -6,7 +6,7 @@
#else
{-# LANGUAGE OverlappingInstances #-}
#endif
-{- Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+{- Copyright (C) 2012-2017 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
@@ -25,7 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Custom
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -41,6 +41,7 @@ import Control.Monad (when)
import Data.Char (toLower)
import Data.List (intersperse)
import qualified Data.Map as M
+import Data.Text (Text, pack)
import Data.Typeable
import GHC.IO.Encoding (getForeignEncoding, setForeignEncoding, utf8)
import Scripting.Lua (LuaState, StackValue, callfunc)
@@ -116,7 +117,7 @@ data PandocLuaException = PandocLuaException String
instance Exception PandocLuaException
-- | Convert Pandoc to custom markup.
-writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO String
+writeCustom :: FilePath -> WriterOptions -> Pandoc -> IO Text
writeCustom luaFile opts doc@(Pandoc meta _) = do
luaScript <- UTF8.readFile luaFile
enc <- getForeignEncoding
@@ -139,8 +140,9 @@ writeCustom luaFile opts doc@(Pandoc meta _) = do
setForeignEncoding enc
let body = rendered
case writerTemplate opts of
- Nothing -> return body
- Just tpl -> return $ renderTemplate' tpl $ setField "body" body context
+ Nothing -> return $ pack body
+ Just tpl -> return $ pack $
+ renderTemplate' tpl $ setField "body" body context
docToCustom :: LuaState -> WriterOptions -> Pandoc -> IO String
docToCustom lua opts (Pandoc (Meta metamap) blocks) = do
diff --git a/src/Text/Pandoc/Writers/Docbook.hs b/src/Text/Pandoc/Writers/Docbook.hs
index dce2cbd3e..02ffbf831 100644
--- a/src/Text/Pandoc/Writers/Docbook.hs
+++ b/src/Text/Pandoc/Writers/Docbook.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Docbook
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -32,6 +32,7 @@ Conversion of 'Pandoc' documents to Docbook XML.
module Text.Pandoc.Writers.Docbook ( writeDocbook4, writeDocbook5 ) where
import Control.Monad.Reader
import Data.Char (toLower)
+import Data.Text (Text)
import Data.Generics (everywhere, mkT)
import Data.List (intercalate, isPrefixOf, isSuffixOf, stripPrefix)
import Data.Monoid (Any (..))
@@ -81,22 +82,23 @@ authorToDocbook opts name' = do
in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
inTagsSimple "surname" (text $ escapeStringForXML lastname)
-writeDocbook4 :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeDocbook4 :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeDocbook4 opts d =
runReaderT (writeDocbook opts d) DocBook4
-writeDocbook5 :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeDocbook5 :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeDocbook5 opts d =
runReaderT (writeDocbook opts d) DocBook5
-- | Convert Pandoc document to string in Docbook format.
-writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> DB m String
+writeDocbook :: PandocMonad m => WriterOptions -> Pandoc -> DB m Text
writeDocbook opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
let opts' = if (maybe False (("/book>" `isSuffixOf`) . trimr)
(writerTemplate opts) &&
TopLevelDefault == writerTopLevelDivision opts)
@@ -111,10 +113,10 @@ writeDocbook opts (Pandoc meta blocks) = do
auths' <- mapM (authorToDocbook opts) $ docAuthors meta
let meta' = B.setMeta "author" auths' meta
metadata <- metaToJSON opts
- (fmap (render colwidth . vcat) .
+ (fmap (render' . vcat) .
(mapM (elementToDocbook opts' startLvl) .
hierarchicalize))
- (fmap (render colwidth) . inlinesToDocbook opts')
+ (fmap render' . inlinesToDocbook opts')
meta'
main <- (render' . vcat) <$> (mapM (elementToDocbook opts' startLvl) elements)
let context = defField "body" main
diff --git a/src/Text/Pandoc/Writers/Docx.hs b/src/Text/Pandoc/Writers/Docx.hs
index fddec91cc..63bb8a5ae 100644
--- a/src/Text/Pandoc/Writers/Docx.hs
+++ b/src/Text/Pandoc/Writers/Docx.hs
@@ -4,7 +4,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2012-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2012-2017 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
@@ -23,7 +23,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Docx
- Copyright : Copyright (C) 2012-2015 John MacFarlane
+ Copyright : Copyright (C) 2012-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -55,7 +55,6 @@ import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
import Text.Pandoc.Compat.Time
import Text.Pandoc.Definition
-import Text.Pandoc.Error
import Text.Pandoc.Generic
import Text.Pandoc.Highlighting (highlight)
import Text.Pandoc.ImageSize
@@ -497,6 +496,11 @@ writeDocx opts doc@(Pandoc meta _) = do
, qName (elName e) == "abstractNum" ] ++
[Elem e | e <- allElts
, qName (elName e) == "num" ] }
+
+ let keywords = case lookupMeta "keywords" meta of
+ Just (MetaList xs) -> map stringify xs
+ _ -> []
+
let docPropsPath = "docProps/core.xml"
let docProps = mknode "cp:coreProperties"
[("xmlns:cp","http://schemas.openxmlformats.org/package/2006/metadata/core-properties")
@@ -506,6 +510,7 @@ writeDocx opts doc@(Pandoc meta _) = do
,("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")]
$ mknode "dc:title" [] (stringify $ docTitle meta)
: mknode "dc:creator" [] (intercalate "; " (map stringify $ docAuthors meta))
+ : mknode "cp:keywords" [] (intercalate ", " keywords)
: (\x -> [ mknode "dcterms:created" [("xsi:type","dcterms:W3CDTF")] x
, mknode "dcterms:modified" [("xsi:type","dcterms:W3CDTF")] x
]) (formatTime defaultTimeLocale "%FT%XZ" utctime)
@@ -876,7 +881,7 @@ blockToOpenXML' opts (Para [Image attr alt (src,'f':'i':'g':':':tit)]) = do
let prop = pCustomStyle $
if null alt
then "Figure"
- else "FigureWithCaption"
+ else "CaptionedFigure"
paraProps <- local (\env -> env { envParaProperties = prop : envParaProperties env }) (getParaProps False)
contents <- inlinesToOpenXML opts [Image attr alt (src,tit)]
captionNode <- withParaProp (pCustomStyle "ImageCaption")
@@ -954,7 +959,7 @@ blockToOpenXML' opts (Table caption aligns widths headers rows) = do
caption' ++
[mknode "w:tbl" []
( mknode "w:tblPr" []
- ( mknode "w:tblStyle" [("w:val","TableNormal")] () :
+ ( mknode "w:tblStyle" [("w:val","Table")] () :
mknode "w:tblW" [("w:type", "pct"), ("w:w", show rowwidth)] () :
mknode "w:tblLook" [("w:firstRow","1") | hasHeader ] () :
[ mknode "w:tblCaption" [("w:val", captionStr)] ()
@@ -1060,13 +1065,24 @@ withParaPropM :: PandocMonad m => WS m Element -> WS m a -> WS m a
withParaPropM = (. flip withParaProp) . (>>=)
formattedString :: PandocMonad m => String -> WS m [Element]
-formattedString str = do
- props <- getTextProps
+formattedString str =
+ -- properly handle soft hyphens
+ case splitBy (=='\173') str of
+ [w] -> formattedString' w
+ ws -> do
+ sh <- formattedRun [mknode "w:softHyphen" [] ()]
+ (intercalate sh) <$> mapM formattedString' ws
+
+formattedString' :: PandocMonad m => String -> WS m [Element]
+formattedString' str = do
inDel <- asks envInDel
- return [ mknode "w:r" [] $
- props ++
- [ mknode (if inDel then "w:delText" else "w:t")
- [("xml:space","preserve")] (stripInvalidChars str) ] ]
+ formattedRun [ mknode (if inDel then "w:delText" else "w:t")
+ [("xml:space","preserve")] (stripInvalidChars str) ]
+
+formattedRun :: PandocMonad m => [Element] -> WS m [Element]
+formattedRun els = do
+ props <- getTextProps
+ return [ mknode "w:r" [] $ props ++ els ]
setFirstPara :: PandocMonad m => WS m ()
setFirstPara = modify $ \s -> s { stFirstPara = True }
@@ -1076,7 +1092,8 @@ inlineToOpenXML :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
inlineToOpenXML opts il = withDirection $ inlineToOpenXML' opts il
inlineToOpenXML' :: PandocMonad m => WriterOptions -> Inline -> WS m [Element]
-inlineToOpenXML' _ (Str str) = formattedString str
+inlineToOpenXML' _ (Str str) =
+ formattedString str
inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
inlineToOpenXML' opts (Span (ident,classes,kvs) ils) = do
@@ -1303,12 +1320,10 @@ inlineToOpenXML' opts (Image attr alt (src, title)) = do
M.insert src (ident, imgpath, mbMimeType, imgElt, img)
$ stImages st }
return [imgElt])
- (\e -> do case e of
- PandocIOError _ e' ->
- report $ CouldNotFetchResource src (show e')
- e' -> report $ CouldNotFetchResource src (show e')
- -- emit alt text
- inlinesToOpenXML opts alt)
+ (\e -> do
+ report $ CouldNotFetchResource src (show e)
+ -- emit alt text
+ inlinesToOpenXML opts alt)
br :: Element
br = breakElement "textWrapping"
diff --git a/src/Text/Pandoc/Writers/DokuWiki.hs b/src/Text/Pandoc/Writers/DokuWiki.hs
index 5e29acbaf..551a1b0b5 100644
--- a/src/Text/Pandoc/Writers/DokuWiki.hs
+++ b/src/Text/Pandoc/Writers/DokuWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Clare Macrae <clare.macrae@googlemail.com>
@@ -44,13 +44,13 @@ import Control.Monad.Reader (ReaderT, ask, local, runReaderT)
import Control.Monad.State (StateT, evalStateT, gets, modify)
import Data.Default (Default (..))
import Data.List (intercalate, intersect, isPrefixOf, transpose)
-import Network.URI (isURI)
+import Data.Text (Text, pack)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents, writerTemplate, writerWrapText))
-import Text.Pandoc.Shared (camelCaseToHyphenated, escapeURI, linesToPara,
+import Text.Pandoc.Shared (camelCaseToHyphenated, escapeURI, isURI, linesToPara,
removeFormatting, substitute, trimr)
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Writers.Shared (defField, metaToJSON)
@@ -76,7 +76,7 @@ instance Default WriterEnvironment where
type DokuWiki m = ReaderT WriterEnvironment (StateT WriterState m)
-- | Convert Pandoc to DokuWiki.
-writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeDokuWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeDokuWiki opts document =
runDokuWiki (pandocToDokuWiki opts document)
@@ -85,7 +85,7 @@ runDokuWiki = flip evalStateT def . flip runReaderT def
-- | Return DokuWiki representation of document.
pandocToDokuWiki :: PandocMonad m
- => WriterOptions -> Pandoc -> DokuWiki m String
+ => WriterOptions -> Pandoc -> DokuWiki m Text
pandocToDokuWiki opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
(fmap trimr . blockListToDokuWiki opts)
@@ -97,7 +97,7 @@ pandocToDokuWiki opts (Pandoc meta blocks) = do
then "" -- TODO Was "\n<references />" Check whether I can really remove this:
-- if it is definitely to do with footnotes, can remove this whole bit
else ""
- let main = body ++ notes
+ let main = pack $ body ++ notes
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts)
$ metadata
diff --git a/src/Text/Pandoc/Writers/EPUB.hs b/src/Text/Pandoc/Writers/EPUB.hs
index 5b64564ce..d68283007 100644
--- a/src/Text/Pandoc/Writers/EPUB.hs
+++ b/src/Text/Pandoc/Writers/EPUB.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2017 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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.EPUB
- Copyright : Copyright (C) 2010-2015 John MacFarlane
+ Copyright : Copyright (C) 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -40,6 +40,7 @@ import Control.Monad.State (State, StateT, evalState, evalStateT, get, gets,
lift, modify, put)
import qualified Data.ByteString.Lazy as B
import qualified Data.ByteString.Lazy.Char8 as B8
+import qualified Data.Text.Lazy as TL
import Data.Char (isAlphaNum, isDigit, toLower)
import Data.List (intercalate, isInfixOf, isPrefixOf)
import qualified Data.Map as M
@@ -373,8 +374,8 @@ pandocToEPUB :: PandocMonad m
-> E m B.ByteString
pandocToEPUB version opts doc@(Pandoc meta _) = do
let epub3 = version == EPUB3
- let writeHtml o = fmap UTF8.fromStringLazy .
- writeHtmlStringForEPUB version o
+ let writeHtml o = fmap (UTF8.fromTextLazy . TL.fromStrict) .
+ writeHtmlStringForEPUB version o
epochtime <- floor <$> lift P.getPOSIXTime
metadata <- getEPUBMetadata opts meta
let mkEntry path content = toEntry path epochtime content
diff --git a/src/Text/Pandoc/Writers/FB2.hs b/src/Text/Pandoc/Writers/FB2.hs
index fb232e278..213756330 100644
--- a/src/Text/Pandoc/Writers/FB2.hs
+++ b/src/Text/Pandoc/Writers/FB2.hs
@@ -1,8 +1,8 @@
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (c) 2011-2012, Sergey Astanin
-All rights reserved.
+Copyright (c) 2011-2012 Sergey Astanin
+ 2012-2017 John MacFarlane
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,17 @@ along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-}
-{- | Conversion of 'Pandoc' documents to FB2 (FictionBook2) format.
+{- |
+Module : Text.Pandoc.Writers.FB2
+Copyright : Copyright (C) 2011-2012 Sergey Astanin
+ 2012-2017 John MacFarlane
+License : GNU GPL, version 2 or above
+
+Maintainer : John MacFarlane
+Stability : alpha
+Portability : portable
+
+Conversion of 'Pandoc' documents to FB2 (FictionBook2) format.
FictionBook is an XML-based e-book format. For more information see:
<http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1>
@@ -34,9 +44,9 @@ import Data.ByteString.Base64 (encode)
import qualified Data.ByteString.Char8 as B8
import Data.Char (isAscii, isControl, isSpace, toLower)
import Data.Either (lefts, rights)
+import Data.Text (Text, pack)
import Data.List (intercalate, intersperse, isPrefixOf, stripPrefix)
import Network.HTTP (urlEncode)
-import Network.URI (isURI)
import Text.XML.Light
import qualified Text.XML.Light as X
import qualified Text.XML.Light.Cursor as XC
@@ -47,7 +57,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Error
import Text.Pandoc.Logging
import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..), def)
-import Text.Pandoc.Shared (capitalize, isHeaderBlock, linesToPara,
+import Text.Pandoc.Shared (capitalize, isHeaderBlock, isURI, linesToPara,
orderedListMarkers)
-- | Data to be written at the end of the document:
@@ -77,13 +87,13 @@ instance Show ImageMode where
writeFB2 :: PandocMonad m
=> WriterOptions -- ^ conversion options
-> Pandoc -- ^ document to convert
- -> m String -- ^ FictionBook2 document (not encoded yet)
+ -> m Text -- ^ FictionBook2 document (not encoded yet)
writeFB2 opts doc = flip evalStateT newFB $ pandocToFB2 opts doc
pandocToFB2 :: PandocMonad m
=> WriterOptions
-> Pandoc
- -> FBM m String
+ -> FBM m Text
pandocToFB2 opts (Pandoc meta blocks) = do
modify (\s -> s { writerOptions = opts })
desc <- description meta
@@ -94,7 +104,7 @@ pandocToFB2 opts (Pandoc meta blocks) = do
(imgs,missing) <- liftM imagesToFetch get >>= \s -> lift (fetchImages s)
let body' = replaceImagesWithAlt missing body
let fb2_xml = el "FictionBook" (fb2_attrs, [desc, body'] ++ notes ++ imgs)
- return $ xml_head ++ (showContent fb2_xml) ++ "\n"
+ return $ pack $ 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 9f41f77d1..5ee8ab4ce 100644
--- a/src/Text/Pandoc/Writers/HTML.hs
+++ b/src/Text/Pandoc/Writers/HTML.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.HTML
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -45,6 +45,8 @@ module Text.Pandoc.Writers.HTML (
) where
import Control.Monad.State
import Data.Char (ord, toLower)
+import Data.Text (Text)
+import qualified Data.Text.Lazy as TL
import Data.List (intersperse, isPrefixOf)
import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
import Data.Monoid ((<>))
@@ -67,7 +69,7 @@ import Text.Pandoc.Writers.Shared
import Text.Pandoc.XML (escapeStringForXML, fromEntities)
#if MIN_VERSION_blaze_markup(0,6,3)
#else
-import Text.Blaze.Internal (preEscapedString)
+import Text.Blaze.Internal (preEscapedString, preEscapedText)
#endif
#if MIN_VERSION_blaze_html(0,5,1)
import qualified Text.Blaze.XHtml5 as H5
@@ -77,7 +79,7 @@ import qualified Text.Blaze.Html5 as H5
import Control.Monad.Except (throwError)
import Data.Aeson (Value)
import System.FilePath (takeExtension, takeBaseName)
-import Text.Blaze.Html.Renderer.String (renderHtml)
+import Text.Blaze.Html.Renderer.Text (renderHtml)
import qualified Text.Blaze.XHtml1.Transitional as H
import qualified Text.Blaze.XHtml1.Transitional.Attributes as A
import Text.Pandoc.Class (PandocMonad, report)
@@ -123,7 +125,7 @@ nl opts = if writerWrapText opts == WrapNone
else preEscapedString "\n"
-- | Convert Pandoc document to Html 5 string.
-writeHtml5String :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeHtml5String :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeHtml5String = writeHtmlString'
defaultWriterState{ stHtml5 = True }
@@ -132,7 +134,7 @@ writeHtml5 :: PandocMonad m => WriterOptions -> Pandoc -> m Html
writeHtml5 = writeHtml' defaultWriterState{ stHtml5 = True }
-- | Convert Pandoc document to Html 4 string.
-writeHtml4String :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeHtml4String :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeHtml4String = writeHtmlString'
defaultWriterState{ stHtml5 = False }
@@ -142,38 +144,39 @@ writeHtml4 = writeHtml' defaultWriterState{ stHtml5 = False }
-- | Convert Pandoc document to Html appropriate for an epub version.
writeHtmlStringForEPUB :: PandocMonad m
- => EPUBVersion -> WriterOptions -> Pandoc -> m String
-writeHtmlStringForEPUB version = writeHtmlString'
+ => EPUBVersion -> WriterOptions -> Pandoc
+ -> m Text
+writeHtmlStringForEPUB version o = writeHtmlString'
defaultWriterState{ stHtml5 = version == EPUB3,
- stEPUBVersion = Just version }
+ stEPUBVersion = Just version } o
-- | Convert Pandoc document to Reveal JS HTML slide show.
writeRevealJs :: PandocMonad m
- => WriterOptions -> Pandoc -> m String
+ => WriterOptions -> Pandoc -> m Text
writeRevealJs = writeHtmlSlideShow' RevealJsSlides
-- | Convert Pandoc document to S5 HTML slide show.
writeS5 :: PandocMonad m
- => WriterOptions -> Pandoc -> m String
+ => WriterOptions -> Pandoc -> m Text
writeS5 = writeHtmlSlideShow' S5Slides
-- | Convert Pandoc document to Slidy HTML slide show.
writeSlidy :: PandocMonad m
- => WriterOptions -> Pandoc -> m String
+ => WriterOptions -> Pandoc -> m Text
writeSlidy = writeHtmlSlideShow' SlidySlides
-- | Convert Pandoc document to Slideous HTML slide show.
writeSlideous :: PandocMonad m
- => WriterOptions -> Pandoc -> m String
+ => WriterOptions -> Pandoc -> m Text
writeSlideous = writeHtmlSlideShow' SlideousSlides
-- | Convert Pandoc document to DZSlides HTML slide show.
writeDZSlides :: PandocMonad m
- => WriterOptions -> Pandoc -> m String
+ => WriterOptions -> Pandoc -> m Text
writeDZSlides = writeHtmlSlideShow' DZSlides
writeHtmlSlideShow' :: PandocMonad m
- => HTMLSlideVariant -> WriterOptions -> Pandoc -> m String
+ => HTMLSlideVariant -> WriterOptions -> Pandoc -> m Text
writeHtmlSlideShow' variant = writeHtmlString'
defaultWriterState{ stSlideVariant = variant
, stHtml5 = case variant of
@@ -185,12 +188,15 @@ writeHtmlSlideShow' variant = writeHtmlString'
NoSlides -> False
}
+renderHtml' :: Html -> Text
+renderHtml' = TL.toStrict . renderHtml
+
writeHtmlString' :: PandocMonad m
- => WriterState -> WriterOptions -> Pandoc -> m String
+ => WriterState -> WriterOptions -> Pandoc -> m Text
writeHtmlString' st opts d = do
(body, context) <- evalStateT (pandocToHtml opts d) st
case writerTemplate opts of
- Nothing -> return $ renderHtml body
+ Nothing -> return $ renderHtml' body
Just tpl -> do
-- warn if empty lang
when (isNothing (getField "lang" context :: Maybe String)) $
@@ -205,12 +211,12 @@ writeHtmlString' st opts d = do
report $ NoTitleElement fallback
return $ resetField "pagetitle" fallback context
return $ renderTemplate' tpl $
- defField "body" (renderHtml body) context'
+ defField "body" (renderHtml' body) context'
writeHtml' :: PandocMonad m => WriterState -> WriterOptions -> Pandoc -> m Html
writeHtml' st opts d = do
case writerTemplate opts of
- Just _ -> preEscapedString <$> writeHtmlString' st opts d
+ Just _ -> preEscapedText <$> writeHtmlString' st opts d
Nothing -> do
(body, _) <- evalStateT (pandocToHtml opts d) st
return body
@@ -222,8 +228,8 @@ pandocToHtml :: PandocMonad m
-> StateT WriterState m (Html, Value)
pandocToHtml opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
- (fmap renderHtml . blockListToHtml opts)
- (fmap renderHtml . inlineListToHtml opts)
+ (fmap renderHtml' . blockListToHtml opts)
+ (fmap renderHtml' . inlineListToHtml opts)
meta
let stringifyHTML = escapeStringForXML . stringify
let authsMeta = map stringifyHTML $ docAuthors meta
@@ -277,10 +283,10 @@ pandocToHtml opts (Pandoc meta blocks) = do
Nothing -> id
else id) $
(if stMath st
- then defField "math" (renderHtml math)
+ then defField "math" (renderHtml' math)
else id) $
defField "quotes" (stQuotes st) $
- maybe id (defField "toc" . renderHtml) toc $
+ maybe id (defField "toc" . renderHtml') toc $
defField "author-meta" authsMeta $
maybe id (defField "date-meta") (normalizeDate dateMeta) $
defField "pagetitle" (stringifyHTML (docTitle meta)) $
@@ -463,7 +469,7 @@ parseMailto s = do
obfuscateLink :: PandocMonad m => WriterOptions -> Attr -> Html -> String -> m Html
obfuscateLink opts attr txt s | writerEmailObfuscation opts == NoObfuscation =
return $ addAttrs opts attr $ H.a ! A.href (toValue s) $ txt
-obfuscateLink opts attr (renderHtml -> txt) s =
+obfuscateLink opts attr (TL.unpack . renderHtml -> txt) s =
let meth = writerEmailObfuscation opts
s' = map toLower (take 7 s) ++ drop 7 s
in case parseMailto s' of
@@ -521,7 +527,7 @@ attrsToHtml opts (id',classes',keyvals) =
imgAttrsToHtml :: WriterOptions -> Attr -> [Attribute]
imgAttrsToHtml opts attr =
attrsToHtml opts (ident,cls,kvs') ++
- toAttrs (dimensionsToAttrList opts attr)
+ toAttrs (dimensionsToAttrList attr)
where
(ident,cls,kvs) = attr
kvs' = filter isNotDim kvs
@@ -529,14 +535,13 @@ imgAttrsToHtml opts attr =
isNotDim ("height", _) = False
isNotDim _ = True
-dimensionsToAttrList :: WriterOptions -> Attr -> [(String, String)]
-dimensionsToAttrList opts attr = (go Width) ++ (go Height)
+dimensionsToAttrList :: Attr -> [(String, String)]
+dimensionsToAttrList attr = (go Width) ++ (go Height)
where
go dir = case (dimension dir attr) of
- (Just (Percent a)) -> [("style", show dir ++ ":" ++ show (Percent a))]
- (Just dim) -> [(show dir, showInPixel opts dim)]
- _ -> []
-
+ (Just (Pixel a)) -> [(show dir, show a)]
+ (Just x) -> [("style", show dir ++ ":" ++ show x)]
+ Nothing -> []
imageExts :: [String]
imageExts = [ "art", "bmp", "cdr", "cdt", "cpt", "cr2", "crw", "djvu", "erf",
@@ -974,7 +979,7 @@ inlineToHtml opts inline = do
(Link attr txt (s,_)) | "mailto:" `isPrefixOf` s -> do
linkText <- inlineListToHtml opts txt
lift $ obfuscateLink opts attr linkText s
- (Link attr txt (s,tit)) -> do
+ (Link (ident,classes,kvs) txt (s,tit)) -> do
linkText <- inlineListToHtml opts txt
slideVariant <- gets stSlideVariant
let s' = case s of
@@ -984,13 +989,13 @@ inlineToHtml opts inline = do
in '#' : prefix ++ xs
_ -> s
let link = H.a ! A.href (toValue s') $ linkText
- let link' = if txt == [Str (unEscapeString s)]
- then link ! A.class_ "uri"
- else link
- let link'' = addAttrs opts attr link'
+ let attr = if txt == [Str (unEscapeString s)]
+ then (ident, "uri" : classes, kvs)
+ else (ident, classes, kvs)
+ let link' = addAttrs opts attr link
return $ if null tit
- then link''
- else link'' ! A.title (toValue tit)
+ then link'
+ else link' ! A.title (toValue tit)
(Image attr txt (s,tit)) | treatAsImage s -> do
let alternate' = stringify txt
slideVariant <- gets stSlideVariant
diff --git a/src/Text/Pandoc/Writers/Haddock.hs b/src/Text/Pandoc/Writers/Haddock.hs
index eae1377cd..1ad9acd40 100644
--- a/src/Text/Pandoc/Writers/Haddock.hs
+++ b/src/Text/Pandoc/Writers/Haddock.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2014 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2014-2015, 2017 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.Writers.Haddock
- Copyright : Copyright (C) 2014 John MacFarlane
+ Copyright : Copyright (C) 2014-2015,2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,8 +35,8 @@ Haddock: <http://www.haskell.org/haddock/doc/html/>
module Text.Pandoc.Writers.Haddock (writeHaddock) where
import Control.Monad.State
import Data.Default
+import Data.Text (Text)
import Data.List (intersperse, transpose)
-import Network.URI (isURI)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Logging
@@ -53,14 +53,14 @@ instance Default WriterState
where def = WriterState{ stNotes = [] }
-- | Convert Pandoc to Haddock.
-writeHaddock :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeHaddock :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeHaddock opts document =
evalStateT (pandocToHaddock opts{
writerWrapText = writerWrapText opts } document) def
-- | Return haddock representation of document.
pandocToHaddock :: PandocMonad m
- => WriterOptions -> Pandoc -> StateT WriterState m String
+ => WriterOptions -> Pandoc -> StateT WriterState m Text
pandocToHaddock opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
@@ -68,13 +68,13 @@ pandocToHaddock opts (Pandoc meta blocks) = do
body <- blockListToHaddock opts blocks
st <- get
notes' <- notesToHaddock opts (reverse $ stNotes st)
- let render' :: Doc -> String
+ let render' :: Doc -> Text
render' = render colwidth
let main = render' $ body <>
(if isEmpty notes' then empty else blankline <> notes')
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToHaddock opts)
- (fmap (render colwidth) . inlineListToHaddock opts)
+ (fmap render' . blockListToHaddock opts)
+ (fmap render' . inlineListToHaddock opts)
meta
let context = defField "body" main
$ metadata
diff --git a/src/Text/Pandoc/Writers/ICML.hs b/src/Text/Pandoc/Writers/ICML.hs
index cd3cac5a7..2884bc532 100644
--- a/src/Text/Pandoc/Writers/ICML.hs
+++ b/src/Text/Pandoc/Writers/ICML.hs
@@ -4,7 +4,7 @@
{- |
Module : Text.Pandoc.Writers.ICML
- Copyright : Copyright (C) 2013-2016 github.com/mb21
+ Copyright : Copyright (C) 2013-2017 github.com/mb21
License : GNU GPL, version 2 or above
Stability : alpha
@@ -21,16 +21,15 @@ import Control.Monad.State
import Data.List (intersperse, isInfixOf, isPrefixOf, stripPrefix)
import qualified Data.Set as Set
import Data.Text as Text (breakOnAll, pack)
-import Network.URI (isURI)
+import Data.Text (Text)
import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
-import Text.Pandoc.Error (PandocError (..))
import Text.Pandoc.ImageSize
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Pretty
-import Text.Pandoc.Shared (linesToPara, splitBy)
+import Text.Pandoc.Shared (isURI, linesToPara, splitBy)
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Writers.Math (texMathToInlines)
import Text.Pandoc.Writers.Shared
@@ -129,11 +128,12 @@ footnoteName = "Footnote"
citeName = "Cite"
-- | Convert Pandoc document to string in ICML format.
-writeICML :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeICML :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeICML opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ render' :: Doc -> Text
render' = render colwidth
renderMeta f s = liftM (render' . fst) $ runStateT (f opts [] s) defaultWriterState
metadata <- metaToJSON opts
@@ -550,10 +550,7 @@ imageICML opts style attr (src, _) = do
report $ CouldNotDetermineImageSize src msg
return def)
(\e -> do
- case e of
- PandocIOError _ e' ->
- report $ CouldNotFetchResource src (show e')
- e' -> report $ CouldNotFetchResource src (show e')
+ report $ CouldNotFetchResource src (show e)
return def)
let (ow, oh) = sizeInPoints imgS
(imgWidth, imgHeight) = desiredSizeInPoints opts attr imgS
diff --git a/src/Text/Pandoc/Writers/JATS.hs b/src/Text/Pandoc/Writers/JATS.hs
index aca7dc969..1a8d80747 100644
--- a/src/Text/Pandoc/Writers/JATS.hs
+++ b/src/Text/Pandoc/Writers/JATS.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
@@ -33,6 +33,7 @@ https://jats.nlm.nih.gov/publishing/tag-library/1.1d3/element/mml-math.html
module Text.Pandoc.Writers.JATS ( writeJATS ) where
import Control.Monad.Reader
import Data.Char (toLower)
+import Data.Text (Text)
import Data.Generics (everywhere, mkT)
import Data.List (intercalate, isSuffixOf, partition)
import Data.Maybe (fromMaybe)
@@ -81,12 +82,12 @@ authorToJATS opts name' = do
in inTagsSimple "firstname" (text $ escapeStringForXML firstname) $$
inTagsSimple "surname" (text $ escapeStringForXML lastname)
-writeJATS :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeJATS :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeJATS opts d =
runReaderT (docToJATS opts d) JATS1_1
-- | Convert Pandoc document to string in JATS format.
-docToJATS :: PandocMonad m => WriterOptions -> Pandoc -> DB m String
+docToJATS :: PandocMonad m => WriterOptions -> Pandoc -> DB m Text
docToJATS opts (Pandoc meta blocks) = do
let isBackBlock (Div ("refs",_,_) _) = True
isBackBlock _ = False
@@ -96,7 +97,8 @@ docToJATS opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
let opts' = if (maybe False (("/book>" `isSuffixOf`) . trimr)
(writerTemplate opts) &&
TopLevelDefault == writerTopLevelDivision opts)
@@ -111,10 +113,10 @@ docToJATS opts (Pandoc meta blocks) = do
auths' <- mapM (authorToJATS opts) $ docAuthors meta
let meta' = B.setMeta "author" auths' meta
metadata <- metaToJSON opts
- (fmap (render colwidth . vcat) .
+ (fmap (render' . vcat) .
(mapM (elementToJATS opts' startLvl) .
hierarchicalize))
- (fmap (render colwidth) . inlinesToJATS opts')
+ (fmap render' . inlinesToJATS opts')
meta'
main <- (render' . vcat) <$>
(mapM (elementToJATS opts' startLvl) elements)
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 000f4f8fb..80606d510 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Writers.LaTeX
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -42,8 +42,9 @@ import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isPunctuation, ord,
import Data.List (foldl', intercalate, intersperse, isInfixOf, nub, nubBy,
stripPrefix, (\\))
import Data.Maybe (catMaybes, fromMaybe, isJust)
+import Data.Text (Text)
import qualified Data.Text as T
-import Network.URI (isURI, unEscapeString)
+import Network.URI (unEscapeString)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
import Text.Pandoc.Highlighting (formatLaTeXBlock, formatLaTeXInline, highlight,
@@ -114,13 +115,13 @@ startingState options = WriterState {
, stEmptyLine = True }
-- | Convert Pandoc to LaTeX.
-writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeLaTeX options document =
evalStateT (pandocToLaTeX options document) $
startingState options
-- | Convert Pandoc to LaTeX Beamer.
-writeBeamer :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeBeamer :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeBeamer options document =
evalStateT (pandocToLaTeX options document) $
(startingState options){ stBeamer = True }
@@ -128,7 +129,7 @@ writeBeamer options document =
type LW m = StateT WriterState m
pandocToLaTeX :: PandocMonad m
- => WriterOptions -> Pandoc -> LW m String
+ => WriterOptions -> Pandoc -> LW m Text
pandocToLaTeX options (Pandoc meta blocks) = do
-- Strip off final 'references' header if --natbib or --biblatex
let method = writerCiteMethod options
@@ -146,9 +147,11 @@ pandocToLaTeX options (Pandoc meta blocks) = do
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToLaTeX)
- (fmap (render colwidth) . inlineListToLaTeX)
+ (fmap render' . blockListToLaTeX)
+ (fmap render' . inlineListToLaTeX)
meta
let bookClasses = ["memoir","book","report","scrreprt","scrbook"]
let documentClass = case P.parse pDocumentClass "template" template of
@@ -180,8 +183,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
then toSlides blocks''
else return blocks''
body <- mapM (elementToLaTeX options) $ hierarchicalize blocks'''
- (biblioTitle :: String) <- liftM (render colwidth) $ inlineListToLaTeX lastHeader
- let main = render colwidth $ vsep body
+ (biblioTitle :: Text) <- render' <$> inlineListToLaTeX lastHeader
+ let main = render' $ vsep body
st <- get
titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
@@ -1062,6 +1065,9 @@ inlineToLaTeX (Link _ txt (src, _)) =
src' <- stringToLaTeX URLString (escapeURI src)
return $ text ("\\href{" ++ src' ++ "}{") <>
contents <> char '}'
+inlineToLaTeX il@(Image _ _ ('d':'a':'t':'a':':':_, _)) = do
+ report $ InlineNotRendered il
+ return empty
inlineToLaTeX (Image attr _ (source, _)) = do
setEmptyLine False
modify $ \s -> s{ stGraphics = True }
diff --git a/src/Text/Pandoc/Writers/Man.hs b/src/Text/Pandoc/Writers/Man.hs
index 1f3e17c16..0fc6afbdc 100644
--- a/src/Text/Pandoc/Writers/Man.hs
+++ b/src/Text/Pandoc/Writers/Man.hs
@@ -1,5 +1,6 @@
+{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2017 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.Writers.Man
- Copyright : Copyright (C) 2007-2015 John MacFarlane
+ Copyright : Copyright (C) 2007-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +35,8 @@ import Control.Monad.State
import Data.List (intercalate, intersperse, stripPrefix, sort)
import qualified Data.Map as Map
import Data.Maybe (fromMaybe)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.Pandoc.Builder (deleteMeta)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
@@ -62,36 +65,37 @@ defaultWriterState = WriterState { stNotes = []
, stHasTables = False }
-- | Convert Pandoc to Man.
-writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeMan :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMan opts document =
evalStateT (pandocToMan opts document) defaultWriterState
-- | Return groff man representation of document.
-pandocToMan :: PandocMonad m => WriterOptions -> Pandoc -> StateT WriterState m String
+pandocToMan :: PandocMonad m => WriterOptions -> Pandoc -> StateT WriterState m Text
pandocToMan opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
titleText <- inlineListToMan opts $ docTitle meta
let title' = render' titleText
let setFieldsFromTitle =
- case break (== ' ') title' of
- (cmdName, rest) -> case break (=='(') cmdName of
- (xs, '(':ys) | not (null ys) &&
- last ys == ')' ->
+ case T.break (== ' ') title' of
+ (cmdName, rest) -> case T.break (=='(') cmdName of
+ (xs, ys) | "(" `T.isPrefixOf` ys
+ && ")" `T.isSuffixOf` ys ->
defField "title" xs .
- defField "section" (init ys) .
- case splitBy (=='|') rest of
+ defField "section" (T.init $ T.drop 1 ys) .
+ case T.splitOn "|" rest of
(ft:hds) ->
- defField "footer" (trim ft) .
+ defField "footer" (T.strip ft) .
defField "header"
- (trim $ concat hds)
+ (T.strip $ mconcat hds)
[] -> id
_ -> defField "title" title'
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToMan opts)
- (fmap (render colwidth) . inlineListToMan opts)
+ (fmap render' . blockListToMan opts)
+ (fmap render' . inlineListToMan opts)
$ deleteMeta "title" meta
body <- blockListToMan opts blocks
notes <- gets stNotes
diff --git a/src/Text/Pandoc/Writers/Markdown.hs b/src/Text/Pandoc/Writers/Markdown.hs
index 8e3ac3665..3ac677943 100644
--- a/src/Text/Pandoc/Writers/Markdown.hs
+++ b/src/Text/Pandoc/Writers/Markdown.hs
@@ -3,7 +3,7 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Markdown
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,26 +34,25 @@ Conversion of 'Pandoc' documents to markdown-formatted plain text.
Markdown: <http://daringfireball.net/projects/markdown/>
-}
module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
-import Control.Monad.Except (throwError)
import Control.Monad.Reader
import Control.Monad.State
import Data.Char (chr, isPunctuation, isSpace, ord)
import Data.Default
import qualified Data.HashMap.Strict as H
+import qualified Data.Map as M
import Data.List (find, group, intersperse, sortBy, stripPrefix, transpose)
import Data.Maybe (fromMaybe)
import Data.Monoid (Any (..))
import Data.Ord (comparing)
import qualified Data.Set as Set
+import Data.Text (Text)
import qualified Data.Text as T
import qualified Data.Vector as V
import Data.Yaml (Value (Array, Bool, Number, Object, String))
import Network.HTTP (urlEncode)
-import Network.URI (isURI)
import Text.HTML.TagSoup (Tag (..), isTagText, parseTags)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
-import Text.Pandoc.Error
import Text.Pandoc.Logging
import Text.Pandoc.Options
import Text.Pandoc.Parsing hiding (blankline, blanklines, char, space)
@@ -91,6 +90,9 @@ instance Default WriterEnv
data WriterState = WriterState { stNotes :: Notes
, stRefs :: Refs
+ , stKeys :: M.Map Key
+ (M.Map (Target, Attr) Int)
+ , stLastIdx :: Int
, stIds :: Set.Set String
, stNoteNum :: Int
}
@@ -98,12 +100,14 @@ data WriterState = WriterState { stNotes :: Notes
instance Default WriterState
where def = WriterState{ stNotes = []
, stRefs = []
+ , stKeys = M.empty
+ , stLastIdx = 0
, stIds = Set.empty
, stNoteNum = 1
}
-- | Convert Pandoc to Markdown.
-writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMarkdown opts document =
evalMD (pandocToMarkdown opts{
writerWrapText = if isEnabled Ext_hard_line_breaks opts
@@ -113,7 +117,7 @@ writeMarkdown opts document =
-- | Convert Pandoc to plain text (like markdown, but without links,
-- pictures, or inline formatting).
-writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writePlain :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writePlain opts document =
evalMD (pandocToMarkdown opts document) def{ envPlain = True } def
@@ -177,15 +181,17 @@ jsonToYaml (Number n) = text $ show n
jsonToYaml _ = empty
-- | Return markdown representation of document.
-pandocToMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> MD m String
+pandocToMarkdown :: PandocMonad m => WriterOptions -> Pandoc -> MD m Text
pandocToMarkdown opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
isPlain <- asks envPlain
+ let render' :: Doc -> Text
+ render' = render colwidth . chomp
metadata <- metaToJSON'
- (fmap (render colwidth) . blockListToMarkdown opts)
- (fmap (render colwidth) . blockToMarkdown opts . Plain)
+ (fmap render' . blockListToMarkdown opts)
+ (fmap render' . blockToMarkdown opts . Plain)
meta
let title' = maybe empty text $ getField "title" metadata
let authors' = maybe [] (map text) $ getField "author" metadata
@@ -213,8 +219,6 @@ pandocToMarkdown opts (Pandoc meta blocks) = do
else blocks
body <- blockListToMarkdown opts blocks'
notesAndRefs' <- notesAndRefs opts
- let render' :: Doc -> String
- render' = render colwidth . chomp
let main = render' $ body <> notesAndRefs'
let context = defField "toc" (render' toc)
$ defField "body" main
@@ -241,7 +245,7 @@ keyToMarkdown opts (label', (src, tit), attr) = do
else space <> "\"" <> text tit <> "\""
return $ nest 2 $ hang 2
("[" <> label' <> "]:" <> space) (text src <> tit')
- <> linkAttributes opts attr
+ <+> linkAttributes opts attr
-- | Return markdown representation of notes.
notesToMarkdown :: PandocMonad m => WriterOptions -> [[Block]] -> MD m Doc
@@ -471,6 +475,8 @@ blockToMarkdown' opts (Header level attr inlines) = do
space <> attrsToMarkdown attr
| otherwise -> empty
contents <- inlineListToMarkdown opts $
+ -- ensure no newlines; see #3736
+ walk lineBreakToSpace $
if level == 1 && plain
then capitalize inlines
else inlines
@@ -568,7 +574,7 @@ blockToMarkdown' opts t@(Table caption aligns widths headers rows) = do
gridTable opts blockListToMarkdown
(all null headers) aligns' widths' headers rows
| isEnabled Ext_raw_html opts -> fmap (id,) $
- text <$>
+ (text . T.unpack) <$>
(writeHtml5String def $ Pandoc nullMeta [t])
| otherwise -> return $ (id, text "[TABLE]")
return $ nst $ tbl $$ caption'' $$ blankline
@@ -788,7 +794,7 @@ blockListToMarkdown opts blocks = do
isListBlock _ = False
commentSep = if isEnabled Ext_raw_html opts
then RawBlock "html" "<!-- -->\n"
- else RawBlock "markdown" "&nbsp;"
+ else RawBlock "markdown" "&nbsp;\n"
mapM (blockToMarkdown opts) (fixBlocks blocks) >>= return . cat
getKey :: Doc -> Key
@@ -798,20 +804,49 @@ getKey = toKey . render Nothing
-- Prefer label if possible; otherwise, generate a unique key.
getReference :: PandocMonad m => Attr -> Doc -> Target -> MD m Doc
getReference attr label target = do
- st <- get
- let keys = map (\(l,_,_) -> getKey l) (stRefs st)
- case find (\(_,t,a) -> t == target && a == attr) (stRefs st) of
+ refs <- gets stRefs
+ case find (\(_,t,a) -> t == target && a == attr) refs of
Just (ref, _, _) -> return ref
Nothing -> do
- label' <- case getKey label `elem` keys of
- True -> -- label is used; generate numerical label
- case find (\n -> Key n `notElem` keys) $
- map show [1..(10000 :: Integer)] of
- Just x -> return $ text x
- Nothing -> throwError $ PandocSomeError "no unique label"
- False -> return label
- modify (\s -> s{ stRefs = (label', target, attr) : stRefs st })
- return label'
+ keys <- gets stKeys
+ case M.lookup (getKey label) keys of
+ Nothing -> do -- no other refs with this label
+ (lab', idx) <- if isEmpty label
+ then do
+ i <- (+ 1) <$> gets stLastIdx
+ modify $ \s -> s{ stLastIdx = i }
+ return (text (show i), i)
+ else return (label, 0)
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs,
+ stKeys = M.insert (getKey label)
+ (M.insert (target, attr) idx mempty)
+ (stKeys s) })
+ return lab'
+
+ Just km -> do -- we have refs with this label
+ case M.lookup (target, attr) km of
+ Just i -> do
+ let lab' = label <> if i == 0
+ then mempty
+ else text (show i)
+ -- make sure it's in stRefs; it may be
+ -- a duplicate that was printed in a previous
+ -- block:
+ when ((lab', target, attr) `notElem` refs) $
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs })
+ return lab'
+ Nothing -> do -- but this one is to a new target
+ i <- (+ 1) <$> gets stLastIdx
+ modify $ \s -> s{ stLastIdx = i }
+ let lab' = text (show i)
+ modify (\s -> s{
+ stRefs = (lab', target, attr) : refs,
+ stKeys = M.insert (getKey label)
+ (M.insert (target, attr) i km)
+ (stKeys s) })
+ return lab'
-- | Convert list of Pandoc inline elements to markdown.
inlineListToMarkdown :: PandocMonad m => WriterOptions -> [Inline] -> MD m Doc
@@ -821,7 +856,8 @@ inlineListToMarkdown opts lst = do
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
+ -- If a link is followed by another link, or '[', '(' or ':'
+ -- then we don't shortcut
(Link _ _ _):_ -> unshortcutable
Space:(Link _ _ _):_ -> unshortcutable
Space:(Str('[':_)):_ -> unshortcutable
@@ -831,9 +867,17 @@ inlineListToMarkdown opts lst = do
SoftBreak:(Str('[':_)):_ -> unshortcutable
SoftBreak:(RawInline _ ('[':_)):_ -> unshortcutable
SoftBreak:(Cite _ _):_ -> unshortcutable
+ LineBreak:(Link _ _ _):_ -> unshortcutable
+ LineBreak:(Str('[':_)):_ -> unshortcutable
+ LineBreak:(RawInline _ ('[':_)):_ -> unshortcutable
+ LineBreak:(Cite _ _):_ -> unshortcutable
(Cite _ _):_ -> unshortcutable
Str ('[':_):_ -> unshortcutable
+ Str ('(':_):_ -> unshortcutable
+ Str (':':_):_ -> unshortcutable
(RawInline _ ('[':_)):_ -> unshortcutable
+ (RawInline _ ('(':_)):_ -> unshortcutable
+ (RawInline _ (':':_)):_ -> unshortcutable
(RawInline _ (' ':'[':_)):_ -> unshortcutable
_ -> shortcutable
_ -> shortcutable
@@ -890,12 +934,14 @@ inlineToMarkdown opts (Span attrs ils) = do
isEnabled Ext_native_spans opts ->
tagWithAttrs "span" attrs <> contents <> text "</span>"
| otherwise -> contents
+inlineToMarkdown _ (Emph []) = return empty
inlineToMarkdown opts (Emph lst) = do
plain <- asks envPlain
contents <- inlineListToMarkdown opts lst
return $ if plain
then "_" <> contents <> "_"
else "*" <> contents <> "*"
+inlineToMarkdown _ (Strong []) = return empty
inlineToMarkdown opts (Strong lst) = do
plain <- asks envPlain
if plain
@@ -903,6 +949,7 @@ inlineToMarkdown opts (Strong lst) = do
else do
contents <- inlineListToMarkdown opts lst
return $ "**" <> contents <> "**"
+inlineToMarkdown _ (Strikeout []) = return empty
inlineToMarkdown opts (Strikeout lst) = do
contents <- inlineListToMarkdown opts lst
return $ if isEnabled Ext_strikeout opts
@@ -910,6 +957,7 @@ inlineToMarkdown opts (Strikeout lst) = do
else if isEnabled Ext_raw_html opts
then "<s>" <> contents <> "</s>"
else contents
+inlineToMarkdown _ (Superscript []) = return empty
inlineToMarkdown opts (Superscript lst) =
local (\env -> env {envEscapeSpaces = True}) $ do
contents <- inlineListToMarkdown opts lst
@@ -922,6 +970,7 @@ inlineToMarkdown opts (Superscript lst) =
in case mapM toSuperscript rendered of
Just r -> text r
Nothing -> text $ "^(" ++ rendered ++ ")"
+inlineToMarkdown _ (Subscript []) = return empty
inlineToMarkdown opts (Subscript lst) =
local (\env -> env {envEscapeSpaces = True}) $ do
contents <- inlineListToMarkdown opts lst
@@ -1064,7 +1113,8 @@ inlineToMarkdown opts lnk@(Link attr txt (src, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- (text . trim) <$> writeHtml5String def (Pandoc nullMeta [Plain [lnk]])
+ (text . T.unpack . T.strip) <$>
+ writeHtml5String def (Pandoc nullMeta [Plain [lnk]])
| otherwise = do
plain <- asks envPlain
linktext <- inlineListToMarkdown opts txt
@@ -1103,7 +1153,8 @@ inlineToMarkdown opts img@(Image attr alternate (source, tit))
| isEnabled Ext_raw_html opts &&
not (isEnabled Ext_link_attributes opts) &&
attr /= nullAttr = -- use raw HTML
- (text . trim) <$> writeHtml5String def (Pandoc nullMeta [Plain [img]])
+ (text . T.unpack . T.strip) <$>
+ writeHtml5String def (Pandoc nullMeta [Plain [img]])
| otherwise = do
plain <- asks envPlain
let txt = if null alternate || alternate == [Str source]
@@ -1154,3 +1205,8 @@ toSubscript c
Just $ chr (0x2080 + (ord c - 48))
| isSpace c = Just c
| otherwise = Nothing
+
+lineBreakToSpace :: Inline -> Inline
+lineBreakToSpace LineBreak = Space
+lineBreakToSpace SoftBreak = Space
+lineBreakToSpace x = x
diff --git a/src/Text/Pandoc/Writers/MediaWiki.hs b/src/Text/Pandoc/Writers/MediaWiki.hs
index def245e38..c70e5b786 100644
--- a/src/Text/Pandoc/Writers/MediaWiki.hs
+++ b/src/Text/Pandoc/Writers/MediaWiki.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,7 +34,7 @@ import Control.Monad.Reader
import Control.Monad.State
import Data.List (intercalate)
import qualified Data.Set as Set
-import Network.URI (isURI)
+import Data.Text (Text, pack)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
import Text.Pandoc.Definition
@@ -60,14 +60,14 @@ data WriterReader = WriterReader {
type MediaWikiWriter m = ReaderT WriterReader (StateT WriterState m)
-- | Convert Pandoc to MediaWiki.
-writeMediaWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeMediaWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMediaWiki opts document =
let initialState = WriterState { stNotes = False, stOptions = opts }
env = WriterReader { options = opts, listLevel = [], useTags = False }
in evalStateT (runReaderT (pandocToMediaWiki document) env) initialState
-- | Return MediaWiki representation of document.
-pandocToMediaWiki :: PandocMonad m => Pandoc -> MediaWikiWriter m String
+pandocToMediaWiki :: PandocMonad m => Pandoc -> MediaWikiWriter m Text
pandocToMediaWiki (Pandoc meta blocks) = do
opts <- asks options
metadata <- metaToJSON opts
@@ -82,7 +82,8 @@ pandocToMediaWiki (Pandoc meta blocks) = do
let main = body ++ notes
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts) metadata
- return $ case writerTemplate opts of
+ return $ pack
+ $ case writerTemplate opts of
Nothing -> main
Just tpl -> renderTemplate' tpl context
diff --git a/src/Text/Pandoc/Writers/Ms.hs b/src/Text/Pandoc/Writers/Ms.hs
index 534f26a5a..c5c3d9f5b 100644
--- a/src/Text/Pandoc/Writers/Ms.hs
+++ b/src/Text/Pandoc/Writers/Ms.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2007-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2007-2017 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.Ms
- Copyright : Copyright (C) 2007-2015 John MacFarlane
+ Copyright : Copyright (C) 2007-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -44,6 +44,7 @@ import Text.Pandoc.Options
import Text.Pandoc.Writers.Math
import Text.Printf ( printf )
import qualified Data.Text as T
+import Data.Text (Text)
import qualified Data.Map as Map
import Data.Maybe ( catMaybes, fromMaybe )
import Data.List ( intersperse, intercalate, sort )
@@ -85,17 +86,18 @@ type Note = [Block]
type MS = StateT WriterState
-- | Convert Pandoc to Ms.
-writeMs :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeMs :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeMs opts document =
evalStateT (pandocToMs opts document) defaultWriterState
-- | Return groff ms representation of document.
-pandocToMs :: PandocMonad m => WriterOptions -> Pandoc -> MS m String
+pandocToMs :: PandocMonad m => WriterOptions -> Pandoc -> MS m Text
pandocToMs opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON opts
(fmap render' . blockListToMs opts)
(fmap render' . inlineListToMs' opts)
@@ -108,9 +110,9 @@ pandocToMs opts (Pandoc meta blocks) = do
hasHighlighting <- gets stHighlighting
let highlightingMacros = if hasHighlighting
then case writerHighlightStyle opts of
- Nothing -> ""
+ Nothing -> mempty
Just sty -> render' $ styleToMs sty
- else ""
+ else mempty
let context = defField "body" main
$ defField "has-inline-math" hasInlineMath
diff --git a/src/Text/Pandoc/Writers/Muse.hs b/src/Text/Pandoc/Writers/Muse.hs
index 8f6493975..85e0b5467 100644
--- a/src/Text/Pandoc/Writers/Muse.hs
+++ b/src/Text/Pandoc/Writers/Muse.hs
@@ -43,6 +43,7 @@ even though it is supported only in Emacs Muse.
-}
module Text.Pandoc.Writers.Muse (writeMuse) where
import Control.Monad.State
+import Data.Text (Text)
import Data.List (intersperse, transpose, isInfixOf)
import System.FilePath (takeExtension)
import Text.Pandoc.Class (PandocMonad)
@@ -53,6 +54,7 @@ import Text.Pandoc.Shared
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Writers.Math
import Text.Pandoc.Writers.Shared
+import qualified Data.Set as Set
type Notes = [[Block]]
data WriterState =
@@ -60,33 +62,37 @@ data WriterState =
, stOptions :: WriterOptions
, stTopLevel :: Bool
, stInsideBlock :: Bool
+ , stIds :: Set.Set String
}
-- | Convert Pandoc to Muse.
writeMuse :: PandocMonad m
=> WriterOptions
-> Pandoc
- -> m String
+ -> m Text
writeMuse opts document =
let st = WriterState { stNotes = []
, stOptions = opts
, stTopLevel = True
, stInsideBlock = False
+ , stIds = Set.empty
}
in evalStateT (pandocToMuse document) st
-- | Return Muse representation of document.
pandocToMuse :: PandocMonad m
=> Pandoc
- -> StateT WriterState m String
+ -> StateT WriterState m Text
pandocToMuse (Pandoc meta blocks) = do
opts <- gets stOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render Nothing
metadata <- metaToJSON opts
- (fmap (render Nothing) . blockListToMuse)
- (fmap (render Nothing) . inlineListToMuse)
+ (fmap render' . blockListToMuse)
+ (fmap render' . inlineListToMuse)
meta
body <- blockListToMuse blocks
notes <- liftM (reverse . stNotes) get >>= notesToMuse
@@ -184,8 +190,14 @@ blockToMuse (DefinitionList items) = do
let ind = offset label''
return $ hang ind label'' contents
blockToMuse (Header level (ident,_,_) inlines) = do
+ opts <- gets stOptions
contents <- inlineListToMuse inlines
- let attr' = if null ident
+
+ ids <- gets stIds
+ let autoId = uniqueIdent inlines ids
+ modify $ \st -> st{ stIds = Set.insert autoId ids }
+
+ let attr' = if null ident || (isEnabled Ext_auto_identifiers opts && ident == autoId)
then empty
else "#" <> text ident <> cr
let header' = text $ replicate level '*'
@@ -207,7 +219,7 @@ blockToMuse (Table caption _ _ headers rows) = do
let hpipeBlocks sep blocks = hcat $ intersperse sep' blocks
where h = maximum (1 : map height blocks)
sep' = lblock (length sep) $ vcat (map text $ replicate h sep)
- let makeRow sep = hpipeBlocks sep . zipWith lblock widthsInChars
+ let makeRow sep = (" " <>) . (hpipeBlocks sep . zipWith lblock widthsInChars)
let head' = makeRow " || " headers'
let rowSeparator = if noHeaders then " | " else " | "
rows'' <- mapM (\row -> do cols <- mapM blockListToMuse row
@@ -215,7 +227,7 @@ blockToMuse (Table caption _ _ headers rows) = do
let body = vcat rows''
return $ (if noHeaders then empty else head')
$$ body
- $$ (if null caption then empty else "|+ " <> caption' <> " +|")
+ $$ (if null caption then empty else " |+ " <> caption' <> " +|")
$$ blankline
blockToMuse (Div _ bs) = blockListToMuse bs
blockToMuse Null = return empty
diff --git a/src/Text/Pandoc/Writers/Native.hs b/src/Text/Pandoc/Writers/Native.hs
index b031a0231..3ef33f05c 100644
--- a/src/Text/Pandoc/Writers/Native.hs
+++ b/src/Text/Pandoc/Writers/Native.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +30,7 @@ Conversion of a 'Pandoc' document to a string representation.
-}
module Text.Pandoc.Writers.Native ( writeNative )
where
+import Data.Text (Text)
import Data.List (intersperse)
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Definition
@@ -67,7 +68,7 @@ prettyBlock (Div attr blocks) =
prettyBlock block = text $ show block
-- | Prettyprint Pandoc document.
-writeNative :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeNative :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeNative opts (Pandoc meta blocks) = return $
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
diff --git a/src/Text/Pandoc/Writers/ODT.hs b/src/Text/Pandoc/Writers/ODT.hs
index 395ef0a96..1da051380 100644
--- a/src/Text/Pandoc/Writers/ODT.hs
+++ b/src/Text/Pandoc/Writers/ODT.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2008-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,18 +35,18 @@ import Control.Monad.State
import qualified Data.ByteString.Lazy as B
import Data.List (isPrefixOf)
import Data.Maybe (fromMaybe)
+import qualified Data.Text.Lazy as TL
import System.FilePath (takeDirectory, takeExtension, (<.>))
import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
import Text.Pandoc.Definition
-import Text.Pandoc.Error (PandocError (..))
import Text.Pandoc.ImageSize
import Text.Pandoc.Logging
import Text.Pandoc.MIME (extensionFromMimeType, getMimeType)
import Text.Pandoc.Options (WrapOption (..), WriterOptions (..))
import Text.Pandoc.Pretty
import Text.Pandoc.Shared (stringify)
-import Text.Pandoc.UTF8 (fromStringLazy)
+import Text.Pandoc.UTF8 (fromStringLazy, fromTextLazy)
import Text.Pandoc.Walk
import Text.Pandoc.Writers.OpenDocument (writeOpenDocument)
import Text.Pandoc.Writers.Shared (fixDisplayMath)
@@ -89,7 +89,7 @@ pandocToODT opts doc@(Pandoc meta _) = do
newContents <- lift $ writeOpenDocument opts{writerWrapText = WrapNone} doc'
epochtime <- floor `fmap` (lift P.getPOSIXTime)
let contentEntry = toEntry "content.xml" epochtime
- $ fromStringLazy newContents
+ $ fromTextLazy $ TL.fromStrict newContents
picEntries <- gets stEntries
let archive = foldr addEntryToArchive refArchive
$ contentEntry : picEntries
@@ -178,10 +178,7 @@ transformPicMath opts (Image attr@(id', cls, _) lab (src,t)) = catchError
modify $ \st -> st{ stEntries = entry : entries }
return $ Image newattr lab (newsrc, t))
(\e -> do
- case e of
- PandocIOError _ e' ->
- report $ CouldNotFetchResource src (show e')
- e' -> report $ CouldNotFetchResource src (show e')
+ report $ CouldNotFetchResource src (show e)
return $ Emph lab)
transformPicMath _ (Math t math) = do
diff --git a/src/Text/Pandoc/Writers/OPML.hs b/src/Text/Pandoc/Writers/OPML.hs
index 98510c40f..4a0a317fa 100644
--- a/src/Text/Pandoc/Writers/OPML.hs
+++ b/src/Text/Pandoc/Writers/OPML.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE CPP #-}
{-
-Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2017 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.OPML
- Copyright : Copyright (C) 2013-2015 John MacFarlane
+ Copyright : Copyright (C) 2013-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +30,8 @@ Conversion of 'Pandoc' documents to OPML XML.
-}
module Text.Pandoc.Writers.OPML ( writeOPML) where
import Control.Monad.Except (throwError)
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Compat.Time
@@ -45,7 +47,7 @@ import Text.Pandoc.Writers.Shared
import Text.Pandoc.XML
-- | Convert Pandoc document to string in OPML format.
-writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeOPML :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeOPML opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
@@ -54,7 +56,7 @@ writeOPML opts (Pandoc meta blocks) = do
meta' = B.setMeta "date" (B.str $ convertDate $ docDate meta) meta
metadata <- metaToJSON opts
(writeMarkdown def . Pandoc nullMeta)
- (\ils -> trimr <$> (writeMarkdown def $ Pandoc nullMeta [Plain ils]))
+ (\ils -> T.stripEnd <$> (writeMarkdown def $ Pandoc nullMeta [Plain ils]))
meta'
main <- (render colwidth . vcat) <$> (mapM (elementToOPML opts) elements)
let context = defField "body" main metadata
@@ -63,9 +65,9 @@ writeOPML opts (Pandoc meta blocks) = do
Just tpl -> renderTemplate' tpl context
-writeHtmlInlines :: PandocMonad m => [Inline] -> m String
+writeHtmlInlines :: PandocMonad m => [Inline] -> m Text
writeHtmlInlines ils =
- trim <$> (writeHtml5String def $ Pandoc nullMeta [Plain ils])
+ T.strip <$> (writeHtml5String def $ Pandoc nullMeta [Plain ils])
-- date format: RFC 822: Thu, 14 Jul 2005 23:41:05 GMT
showDateTimeRFC822 :: UTCTime -> String
@@ -95,9 +97,10 @@ elementToOPML opts (Sec _ _num _ title elements) = do
(blocks, rest) = span isBlk elements
htmlIls <- writeHtmlInlines title
md <- if null blocks
- then return []
+ then return mempty
else do blks <- mapM fromBlk blocks
writeMarkdown def $ Pandoc nullMeta blks
- let attrs = [("text", htmlIls)] ++ [("_note", md) | not (null blocks)]
+ let attrs = [("text", unpack htmlIls)] ++
+ [("_note", unpack md) | not (null blocks)]
o <- mapM (elementToOPML opts) rest
return $ inTags True "outline" attrs $ vcat o
diff --git a/src/Text/Pandoc/Writers/OpenDocument.hs b/src/Text/Pandoc/Writers/OpenDocument.hs
index 491069343..58295684e 100644
--- a/src/Text/Pandoc/Writers/OpenDocument.hs
+++ b/src/Text/Pandoc/Writers/OpenDocument.hs
@@ -2,7 +2,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2008-2015 Andrea Rossato <andrea.rossato@ing.unitn.it>
+Copyright (C) 2008-2017 Andrea Rossato <andrea.rossato@ing.unitn.it>
and John MacFarlane.
This program is free software; you can redistribute it and/or modify
@@ -22,7 +22,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.OpenDocument
- Copyright : Copyright (C) 2008-2015 Andrea Rossato and John MacFarlane
+ Copyright : Copyright (C) 2008-2017 Andrea Rossato and John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : Andrea Rossato <andrea.rossato@ing.unitn.it>
@@ -36,6 +36,7 @@ import Control.Arrow ((***), (>>>))
import Control.Monad.State hiding (when)
import Data.Char (chr)
import Data.List (sortBy)
+import Data.Text (Text)
import qualified Data.Map as Map
import Data.Ord (comparing)
import qualified Data.Set as Set
@@ -195,17 +196,18 @@ handleSpaces s
rm [] = empty
-- | Convert Pandoc document to string in OpenDocument format.
-writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeOpenDocument :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeOpenDocument opts (Pandoc meta blocks) = do
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
- let render' = render colwidth
+ let render' :: Doc -> Text
+ render' = render colwidth
((body, metadata),s) <- flip runStateT
defaultWriterState $ do
m <- metaToJSON opts
- (fmap (render colwidth) . blocksToOpenDocument opts)
- (fmap (render colwidth) . inlinesToOpenDocument opts)
+ (fmap render' . blocksToOpenDocument opts)
+ (fmap render' . inlinesToOpenDocument opts)
meta
b <- render' `fmap` blocksToOpenDocument opts blocks
return (b, m)
diff --git a/src/Text/Pandoc/Writers/Org.hs b/src/Text/Pandoc/Writers/Org.hs
index fc6608450..e8f48da00 100644
--- a/src/Text/Pandoc/Writers/Org.hs
+++ b/src/Text/Pandoc/Writers/Org.hs
@@ -1,8 +1,8 @@
{-# LANGUAGE OverloadedStrings #-}
{-
Copyright (C) 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
- Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>,
- and John MacFarlane <jgm@berkeley.edu>
+ 2010-2017 John MacFarlane <jgm@berkeley.edu>
+ 2016-2017 Albert Krewinkel <tarleb+pandoc@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
@@ -21,10 +21,12 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Org
- Copyright : Copyright (C) 2010-2015 Puneeth Chaganti and John MacFarlane
+ Copyright : © 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
+ 2010-2017 John MacFarlane <jgm@berkeley.edu>
+ 2016-2017 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
License : GNU GPL, version 2 or above
- Maintainer : Puneeth Chaganti <punchagan@gmail.com>
+ Maintainer : Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
Stability : alpha
Portability : portable
@@ -32,9 +34,10 @@ Conversion of 'Pandoc' documents to Emacs Org-Mode.
Org-Mode: <http://orgmode.org>
-}
-module Text.Pandoc.Writers.Org ( writeOrg) where
+module Text.Pandoc.Writers.Org (writeOrg) where
import Control.Monad.State
import Data.Char (isAlphaNum, toLower)
+import Data.Text (Text)
import Data.List (intersect, intersperse, isPrefixOf, partition, transpose)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
@@ -54,7 +57,7 @@ data WriterState =
type Org = StateT WriterState
-- | Convert Pandoc to Org.
-writeOrg :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeOrg :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeOrg opts document = do
let st = WriterState { stNotes = [],
stHasMath = False,
@@ -62,22 +65,24 @@ writeOrg opts document = do
evalStateT (pandocToOrg document) st
-- | Return Org representation of document.
-pandocToOrg :: PandocMonad m => Pandoc -> Org m String
+pandocToOrg :: PandocMonad m => Pandoc -> Org m Text
pandocToOrg (Pandoc meta blocks) = do
opts <- gets stOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToOrg)
- (fmap (render colwidth) . inlineListToOrg)
+ (fmap render' . blockListToOrg)
+ (fmap render' . inlineListToOrg)
meta
body <- blockListToOrg blocks
notes <- gets (reverse . stNotes) >>= notesToOrg
hasMath <- gets stHasMath
- let main = render colwidth $ foldl ($+$) empty $ [body, notes]
+ let main = render colwidth . foldl ($+$) empty $ [body, notes]
let context = defField "body" main
- $ defField "math" hasMath
+ . defField "math" hasMath
$ metadata
case writerTemplate opts of
Nothing -> return main
@@ -86,8 +91,7 @@ pandocToOrg (Pandoc meta blocks) = do
-- | Return Org representation of notes.
notesToOrg :: PandocMonad m => [[Block]] -> Org m Doc
notesToOrg notes =
- mapM (\(num, note) -> noteToOrg num note) (zip [1..] notes) >>=
- return . vsep
+ vsep <$> zipWithM noteToOrg [1..] notes
-- | Return Org representation of a note.
noteToOrg :: PandocMonad m => Int -> [Block] -> Org m Doc
@@ -219,16 +223,16 @@ blockToOrg (Table caption' _ _ headers rows) = do
-- FIXME: Org doesn't allow blocks with height more than 1.
let hpipeBlocks blocks = hcat [beg, middle, end]
where h = maximum (1 : map height blocks)
- sep' = lblock 3 $ vcat (map text $ replicate h " | ")
- beg = lblock 2 $ vcat (map text $ replicate h "| ")
- end = lblock 2 $ vcat (map text $ replicate h " |")
+ sep' = lblock 3 $ vcat (replicate h (text " | "))
+ beg = lblock 2 $ vcat (replicate h (text "| "))
+ end = lblock 2 $ vcat (replicate h (text " |"))
middle = hcat $ intersperse sep' blocks
let makeRow = hpipeBlocks . zipWith lblock widthsInChars
let head' = makeRow headers'
rows' <- mapM (\row -> do cols <- mapM blockListToOrg row
return $ makeRow cols) rows
let border ch = char '|' <> char ch <>
- (hcat $ intersperse (char ch <> char '+' <> char ch) $
+ (hcat . intersperse (char ch <> char '+' <> char ch) $
map (\l -> text $ replicate l ch) widthsInChars) <>
char ch <> char '|'
let body = vcat rows'
@@ -249,8 +253,7 @@ blockToOrg (OrderedList (start, _, delim) items) = do
let maxMarkerLength = maximum $ map length markers
let markers' = map (\m -> let s = maxMarkerLength - length m
in m ++ replicate s ' ') markers
- contents <- mapM (\(item, num) -> orderedListItemToOrg item num) $
- zip markers' items
+ contents <- zipWithM orderedListItemToOrg markers' items
-- ensure that sublists have preceding blank line
return $ blankline $$ vcat contents $$ blankline
blockToOrg (DefinitionList items) = do
@@ -277,8 +280,8 @@ definitionListItemToOrg :: PandocMonad m
=> ([Inline], [[Block]]) -> Org m Doc
definitionListItemToOrg (label, defs) = do
label' <- inlineListToOrg label
- contents <- liftM vcat $ mapM blockListToOrg defs
- return $ hang 2 "- " $ label' <> " :: " <> (contents <> cr)
+ contents <- vcat <$> mapM blockListToOrg defs
+ return . hang 2 "- " $ label' <> " :: " <> (contents <> cr)
-- | Convert list of key/value pairs to Org :PROPERTIES: drawer.
propertiesDrawer :: Attr -> Doc
@@ -310,13 +313,13 @@ attrHtml (ident, classes, kvs) =
blockListToOrg :: PandocMonad m
=> [Block] -- ^ List of block elements
-> Org m Doc
-blockListToOrg blocks = mapM blockToOrg blocks >>= return . vcat
+blockListToOrg blocks = vcat <$> mapM blockToOrg blocks
-- | Convert list of Pandoc inline elements to Org.
inlineListToOrg :: PandocMonad m
=> [Inline]
-> Org m Doc
-inlineListToOrg lst = mapM inlineToOrg lst >>= return . hcat
+inlineListToOrg lst = hcat <$> mapM inlineToOrg lst
-- | Convert Pandoc inline element to Org.
inlineToOrg :: PandocMonad m => Inline -> Org m Doc
@@ -348,7 +351,7 @@ inlineToOrg (Quoted DoubleQuote lst) = do
return $ "\"" <> contents <> "\""
inlineToOrg (Cite _ lst) = inlineListToOrg lst
inlineToOrg (Code _ str) = return $ "=" <> text str <> "="
-inlineToOrg (Str str) = return $ text $ escapeString str
+inlineToOrg (Str str) = return . text $ escapeString str
inlineToOrg (Math t str) = do
modify $ \st -> st{ stHasMath = True }
return $ if t == InlineMath
diff --git a/src/Text/Pandoc/Writers/RST.hs b/src/Text/Pandoc/Writers/RST.hs
index 24898d62e..59f6553e2 100644
--- a/src/Text/Pandoc/Writers/RST.hs
+++ b/src/Text/Pandoc/Writers/RST.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,7 +35,7 @@ import Control.Monad.State
import Data.Char (isSpace, toLower)
import Data.List (isPrefixOf, stripPrefix)
import Data.Maybe (fromMaybe)
-import Network.URI (isURI)
+import Data.Text (Text, stripEnd)
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
@@ -57,33 +57,36 @@ data WriterState =
, stHasRawTeX :: Bool
, stOptions :: WriterOptions
, stTopLevel :: Bool
+ , stLastNested :: Bool
}
type RST = StateT WriterState
-- | Convert Pandoc to RST.
-writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeRST :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeRST opts document = do
let st = WriterState { stNotes = [], stLinks = [],
stImages = [], stHasMath = False,
stHasRawTeX = False, stOptions = opts,
- stTopLevel = True}
+ stTopLevel = True, stLastNested = False}
evalStateT (pandocToRST document) st
-- | Return RST representation of document.
-pandocToRST :: PandocMonad m => Pandoc -> RST m String
+pandocToRST :: PandocMonad m => Pandoc -> RST m Text
pandocToRST (Pandoc meta blocks) = do
opts <- gets stOptions
let colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
let subtit = case lookupMeta "subtitle" meta of
Just (MetaBlocks [Plain xs]) -> xs
_ -> []
title <- titleToRST (docTitle meta) subtit
metadata <- metaToJSON opts
- (fmap (render colwidth) . blockListToRST)
- (fmap (trimr . render colwidth) . inlineListToRST)
+ (fmap render' . blockListToRST)
+ (fmap (stripEnd . render') . inlineListToRST)
$ B.deleteMeta "title" $ B.deleteMeta "subtitle" meta
body <- blockListToRST' True $ case writerTemplate opts of
Just _ -> normalizeHeadings 1 blocks
@@ -94,7 +97,7 @@ pandocToRST (Pandoc meta blocks) = do
pics <- gets (reverse . stImages) >>= pictRefsToRST
hasMath <- gets stHasMath
rawTeX <- gets stHasRawTeX
- let main = render colwidth $ foldl ($+$) empty $ [body, notes, refs, pics]
+ let main = render' $ foldl ($+$) empty $ [body, notes, refs, pics]
let context = defField "body" main
$ defField "toc" (writerTableOfContents opts)
$ defField "toc-depth" (show $ writerTOCDepth opts)
@@ -343,11 +346,32 @@ blockListToRST' :: PandocMonad m
-> RST m Doc
blockListToRST' topLevel blocks = do
tl <- gets stTopLevel
- modify (\s->s{stTopLevel=topLevel})
- res <- vcat `fmap` mapM blockToRST blocks
+ modify (\s->s{stTopLevel=topLevel, stLastNested=False})
+ res <- vcat `fmap` mapM blockToRST' blocks
modify (\s->s{stTopLevel=tl})
return res
+blockToRST' :: PandocMonad m => Block -> RST m Doc
+blockToRST' (x@BlockQuote{}) = do
+ lastNested <- gets stLastNested
+ res <- blockToRST x
+ modify (\s -> s{stLastNested = True})
+ return $ if lastNested
+ then ".." $+$ res
+ else res
+blockToRST' x = do
+ modify (\s -> s{stLastNested =
+ case x of
+ Para [Image _ _ (_,'f':'i':'g':':':_)] -> True
+ Para{} -> False
+ Plain{} -> False
+ Header{} -> False
+ LineBlock{} -> False
+ HorizontalRule -> False
+ _ -> True
+ })
+ blockToRST x
+
blockListToRST :: PandocMonad m
=> [Block] -- ^ List of block elements
-> RST m Doc
diff --git a/src/Text/Pandoc/Writers/RTF.hs b/src/Text/Pandoc/Writers/RTF.hs
index 67f0fc2e0..5c990f324 100644
--- a/src/Text/Pandoc/Writers/RTF.hs
+++ b/src/Text/Pandoc/Writers/RTF.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE ScopedTypeVariables #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.RTF
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -34,6 +34,8 @@ import Control.Monad.Except (catchError, throwError)
import qualified Data.ByteString as B
import Data.Char (chr, isDigit, ord)
import Data.List (intercalate, isSuffixOf)
+import Data.Text (Text)
+import qualified Data.Text as T
import qualified Data.Map as M
import Text.Pandoc.Class (PandocMonad, report)
import qualified Text.Pandoc.Class as P
@@ -92,15 +94,12 @@ rtfEmbedImage opts x@(Image attr _ (src,_)) = catchError
report $ CouldNotDetermineMimeType src
return x)
(\e -> do
- case e of
- PandocIOError _ e' ->
- report $ CouldNotFetchResource src (show e')
- e' -> report $ CouldNotFetchResource src (show e')
+ report $ CouldNotFetchResource src (show e)
return x)
rtfEmbedImage _ x = return x
-- | Convert Pandoc to a string in rich text format.
-writeRTF :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeRTF :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeRTF options doc = do
-- handle images
Pandoc meta@(Meta metamap) blocks <- walkM (rtfEmbedImage options) doc
@@ -126,7 +125,8 @@ writeRTF options doc = do
then defField "toc" toc
else id)
$ metadata
- return $ case writerTemplate options of
+ return $ T.pack
+ $ case writerTemplate options of
Just tpl -> renderTemplate' tpl context
Nothing -> case reverse body of
('\n':_) -> body
diff --git a/src/Text/Pandoc/Writers/Shared.hs b/src/Text/Pandoc/Writers/Shared.hs
index 615733a78..2047285eb 100644
--- a/src/Text/Pandoc/Writers/Shared.hs
+++ b/src/Text/Pandoc/Writers/Shared.hs
@@ -1,6 +1,6 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2013-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2013-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2013-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -62,10 +62,10 @@ import Text.Pandoc.XML (escapeStringForXML)
-- Variables overwrite metadata fields with the same names.
-- If multiple variables are set with the same name, a list is
-- assigned. Does nothing if 'writerTemplate' is Nothing.
-metaToJSON :: (Functor m, Monad m)
+metaToJSON :: (Functor m, Monad m, ToJSON a)
=> WriterOptions
- -> ([Block] -> m String)
- -> ([Inline] -> m String)
+ -> ([Block] -> m a)
+ -> ([Inline] -> m a)
-> Meta
-> m Value
metaToJSON opts blockWriter inlineWriter meta
@@ -75,9 +75,9 @@ metaToJSON opts blockWriter inlineWriter meta
-- | Like 'metaToJSON', but does not include variables and is
-- not sensitive to 'writerTemplate'.
-metaToJSON' :: Monad m
- => ([Block] -> m String)
- -> ([Inline] -> m String)
+metaToJSON' :: (Monad m, ToJSON a)
+ => ([Block] -> m a)
+ -> ([Inline] -> m a)
-> Meta
-> m Value
metaToJSON' blockWriter inlineWriter (Meta metamap) = do
@@ -98,9 +98,9 @@ addVariablesToJSON opts metadata =
where combineMetadata (Object o1) (Object o2) = Object $ H.union o1 o2
combineMetadata x _ = x
-metaValueToJSON :: Monad m
- => ([Block] -> m String)
- -> ([Inline] -> m String)
+metaValueToJSON :: (Monad m, ToJSON a)
+ => ([Block] -> m a)
+ -> ([Inline] -> m a)
-> MetaValue
-> m Value
metaValueToJSON blockWriter inlineWriter (MetaMap metamap) = liftM toJSON $
diff --git a/src/Text/Pandoc/Writers/TEI.hs b/src/Text/Pandoc/Writers/TEI.hs
index 0e1a0526d..27d26c7d9 100644
--- a/src/Text/Pandoc/Writers/TEI.hs
+++ b/src/Text/Pandoc/Writers/TEI.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternGuards #-}
{-
-Copyright (C) 2006-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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.Docbook
- Copyright : Copyright (C) 2006-2015 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -31,6 +31,7 @@ Conversion of 'Pandoc' documents to Docbook XML.
-}
module Text.Pandoc.Writers.TEI (writeTEI) where
import Data.Char (toLower)
+import Data.Text (Text)
import Data.List (isPrefixOf, stripPrefix)
import qualified Text.Pandoc.Builder as B
import Text.Pandoc.Class (PandocMonad, report)
@@ -56,12 +57,13 @@ authorToTEI opts name' = do
inTagsSimple "author" (text $ escapeStringForXML name)
-- | Convert Pandoc document to string in Docbook format.
-writeTEI :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeTEI :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeTEI opts (Pandoc meta blocks) = do
let elements = hierarchicalize blocks
colwidth = if writerWrapText opts == WrapAuto
then Just $ writerColumns opts
else Nothing
+ render' :: Doc -> Text
render' = render colwidth
startLvl = case writerTopLevelDivision opts of
TopLevelPart -> -1
@@ -71,9 +73,9 @@ writeTEI opts (Pandoc meta blocks) = do
auths' <- mapM (authorToTEI opts) $ docAuthors meta
let meta' = B.setMeta "author" auths' meta
metadata <- metaToJSON opts
- (fmap (render colwidth . vcat) .
- (mapM (elementToTEI opts startLvl)) . hierarchicalize)
- (fmap (render colwidth) . inlinesToTEI opts)
+ (fmap (render' . vcat) .
+ mapM (elementToTEI opts startLvl) . hierarchicalize)
+ (fmap render' . inlinesToTEI opts)
meta'
main <- (render' . vcat) <$> mapM (elementToTEI opts startLvl) elements
let context = defField "body" main
diff --git a/src/Text/Pandoc/Writers/Texinfo.hs b/src/Text/Pandoc/Writers/Texinfo.hs
index da4f43ee5..387e55290 100644
--- a/src/Text/Pandoc/Writers/Texinfo.hs
+++ b/src/Text/Pandoc/Writers/Texinfo.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-
-Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+Copyright (C) 2008-2017 John MacFarlane
+ 2012 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 +20,8 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{- |
Module : Text.Pandoc.Writers.Texinfo
- Copyright : Copyright (C) 2008-2015 John MacFarlane and Peter Wang
+ Copyright : Copyright (C) 2008-2017 John MacFarlane
+ 2012 Peter Wang
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -35,7 +37,8 @@ import Data.Char (chr, ord)
import Data.List (maximumBy, transpose)
import Data.Ord (comparing)
import qualified Data.Set as Set
-import Network.URI (isURI, unEscapeString)
+import Data.Text (Text)
+import Network.URI (unEscapeString)
import System.FilePath
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Definition
@@ -66,7 +69,7 @@ data WriterState =
type TI m = StateT WriterState m
-- | Convert Pandoc to Texinfo.
-writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeTexinfo options document =
evalStateT (pandocToTexinfo options $ wrapTop document) $
WriterState { stStrikeout = False, stSuperscript = False,
@@ -78,16 +81,18 @@ wrapTop :: Pandoc -> Pandoc
wrapTop (Pandoc meta blocks) =
Pandoc meta (Header 0 nullAttr (docTitle meta) : blocks)
-pandocToTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> TI m String
+pandocToTexinfo :: PandocMonad m => WriterOptions -> Pandoc -> TI m Text
pandocToTexinfo options (Pandoc meta blocks) = do
let titlePage = not $ all null
$ docTitle meta : docDate meta : docAuthors meta
let colwidth = if writerWrapText options == WrapAuto
then Just $ writerColumns options
else Nothing
+ let render' :: Doc -> Text
+ render' = render colwidth
metadata <- metaToJSON options
- (fmap (render colwidth) . blockListToTexinfo)
- (fmap (render colwidth) . inlineListToTexinfo)
+ (fmap render' . blockListToTexinfo)
+ (fmap render' . inlineListToTexinfo)
meta
main <- blockListToTexinfo blocks
st <- get
diff --git a/src/Text/Pandoc/Writers/Textile.hs b/src/Text/Pandoc/Writers/Textile.hs
index 0ecb746c3..091a5baca 100644
--- a/src/Text/Pandoc/Writers/Textile.hs
+++ b/src/Text/Pandoc/Writers/Textile.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2010-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2010-2017 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-2015 John MacFarlane
+ Copyright : Copyright (C) 2010-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -33,6 +33,7 @@ module Text.Pandoc.Writers.Textile ( writeTextile ) where
import Control.Monad.State
import Data.Char (isSpace)
import Data.List (intercalate)
+import Data.Text (Text, pack)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
import Text.Pandoc.Definition
@@ -54,7 +55,7 @@ data WriterState = WriterState {
type TW = StateT WriterState
-- | Convert Pandoc to Textile.
-writeTextile :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeTextile :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeTextile opts document =
evalStateT (pandocToTextile opts document)
WriterState { stNotes = [],
@@ -64,17 +65,17 @@ writeTextile opts document =
-- | Return Textile representation of document.
pandocToTextile :: PandocMonad m
- => WriterOptions -> Pandoc -> TW m String
+ => WriterOptions -> Pandoc -> TW m Text
pandocToTextile opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts (blockListToTextile opts)
(inlineListToTextile opts) meta
body <- blockListToTextile opts blocks
notes <- gets $ unlines . reverse . stNotes
- let main = body ++ if null notes then "" else ("\n\n" ++ notes)
+ let main = pack $ body ++ if null notes then "" else ("\n\n" ++ notes)
let context = defField "body" main metadata
case writerTemplate opts of
- Nothing -> return main
- Just tpl -> return $ renderTemplate' tpl context
+ Nothing -> return main
+ Just tpl -> return $ renderTemplate' tpl context
withUseTags :: PandocMonad m => TW m a -> TW m a
withUseTags action = do
diff --git a/src/Text/Pandoc/Writers/ZimWiki.hs b/src/Text/Pandoc/Writers/ZimWiki.hs
index da8b08de1..5ee239e59 100644
--- a/src/Text/Pandoc/Writers/ZimWiki.hs
+++ b/src/Text/Pandoc/Writers/ZimWiki.hs
@@ -1,5 +1,6 @@
{-
-Copyright (C) 2008-2015 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2008-2017 John MacFarlane <jgm@berkeley.edu>
+ 2017 Alex Ivkin
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.Writers.ZimWiki
- Copyright : Copyright (C) 2008-2015 John MacFarlane, 2017 Alex Ivkin
+ Copyright : Copyright (C) 2008-2017 John MacFarlane, 2017 Alex Ivkin
License : GNU GPL, version 2 or above
Maintainer : Alex Ivkin <alex@ivkin.net>
@@ -36,15 +37,14 @@ import Control.Monad.State (StateT, evalStateT, gets, modify)
import Data.Default (Default (..))
import Data.List (intercalate, isInfixOf, isPrefixOf, transpose)
import qualified Data.Map as Map
-import Data.Text (breakOnAll, pack)
-import Network.URI (isURI)
+import Data.Text (breakOnAll, pack, Text)
import Text.Pandoc.Class (PandocMonad, report)
import Text.Pandoc.Logging
import Text.Pandoc.Definition
import Text.Pandoc.ImageSize
import Text.Pandoc.Options (WrapOption (..), WriterOptions (writerTableOfContents, writerTemplate, writerWrapText))
-import Text.Pandoc.Shared (escapeURI, linesToPara, removeFormatting, substitute,
- trimr)
+import Text.Pandoc.Shared (isURI, escapeURI, linesToPara, removeFormatting,
+ substitute, trimr)
import Text.Pandoc.Templates (renderTemplate')
import Text.Pandoc.Writers.Shared (defField, metaToJSON)
@@ -61,17 +61,17 @@ instance Default WriterState where
type ZW = StateT WriterState
-- | Convert Pandoc to ZimWiki.
-writeZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> m String
+writeZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeZimWiki opts document = evalStateT (pandocToZimWiki opts document) def
-- | Return ZimWiki representation of document.
-pandocToZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> ZW m String
+pandocToZimWiki :: PandocMonad m => WriterOptions -> Pandoc -> ZW m Text
pandocToZimWiki opts (Pandoc meta blocks) = do
metadata <- metaToJSON opts
(fmap trimr . blockListToZimWiki opts)
(inlineListToZimWiki opts)
meta
- body <- blockListToZimWiki opts blocks
+ body <- pack <$> blockListToZimWiki opts blocks
--let header = "Content-Type: text/x-zim-wiki\nWiki-Format: zim 0.4\n"
let main = body
let context = defField "body" main
diff --git a/src/Text/Pandoc/XML.hs b/src/Text/Pandoc/XML.hs
index d7fdc4278..67608fb43 100644
--- a/src/Text/Pandoc/XML.hs
+++ b/src/Text/Pandoc/XML.hs
@@ -1,5 +1,5 @@
{-
-Copyright (C) 2006-2016 John MacFarlane <jgm@berkeley.edu>
+Copyright (C) 2006-2017 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-2016 John MacFarlane
+ Copyright : Copyright (C) 2006-2017 John MacFarlane
License : GNU GPL, version 2 or above
Maintainer : John MacFarlane <jgm@berkeley.edu>
@@ -37,6 +37,8 @@ module Text.Pandoc.XML ( escapeCharForXML,
fromEntities ) where
import Data.Char (isAscii, isSpace, ord)
+import Data.Text (Text)
+import qualified Data.Text as T
import Text.HTML.TagSoup.Entity (lookupEntity)
import Text.Pandoc.Pretty
@@ -91,11 +93,10 @@ inTagsIndented :: String -> Doc -> Doc
inTagsIndented tagType = inTags True tagType []
-- | Escape all non-ascii characters using numerical entities.
-toEntities :: String -> String
-toEntities [] = ""
-toEntities (c:cs)
- | isAscii c = c : toEntities cs
- | otherwise = "&#" ++ show (ord c) ++ ";" ++ toEntities cs
+toEntities :: Text -> Text
+toEntities = T.concatMap go
+ where go c | isAscii c = T.singleton c
+ | otherwise = T.pack ("&#" ++ show (ord c) ++ ";")
-- Unescapes XML entities
fromEntities :: String -> String
diff --git a/stack.full.yaml b/stack.full.yaml
index f05ccbce3..e5fff5a4e 100644
--- a/stack.full.yaml
+++ b/stack.full.yaml
@@ -3,7 +3,6 @@
flags:
pandoc:
trypandoc: false
- https: true
embed_data_files: false
old-locale: false
network-uri: true
diff --git a/stack.pkg.yaml b/stack.pkg.yaml
index 864982278..fe5103ecf 100644
--- a/stack.pkg.yaml
+++ b/stack.pkg.yaml
@@ -1,7 +1,6 @@
flags:
pandoc:
trypandoc: false
- https: true
embed_data_files: true
old-locale: false
network-uri: true
@@ -15,9 +14,9 @@ packages:
- '.'
- location:
git: https://github.com/jgm/pandoc-citeproc.git
- commit: 0926289c5ccc1c69c90b2e9132b0e2b57f08aa4d
+ commit: 2e27f5cb40577c9b3ffe0fc112687084f3d9d877
extra-dep: false
extra-deps:
- hslua-0.5.0
- skylighting-0.3.3
-resolver: lts-8.12
+resolver: lts-8.16
diff --git a/stack.yaml b/stack.yaml
index b9f02b364..d9c6b6714 100644
--- a/stack.yaml
+++ b/stack.yaml
@@ -1,7 +1,6 @@
flags:
pandoc:
trypandoc: false
- https: true
embed_data_files: false
old-locale: false
network-uri: true
@@ -10,4 +9,4 @@ packages:
extra-deps:
- hslua-0.5.0
- skylighting-0.3.3
-resolver: lts-8.12
+resolver: lts-8.16
diff --git a/test/Tests/Command.hs b/test/Tests/Command.hs
index 054ceb50d..1f3694f60 100644
--- a/test/Tests/Command.hs
+++ b/test/Tests/Command.hs
@@ -13,6 +13,7 @@ import Test.Tasty.HUnit
import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Shared (trimr)
+import qualified Data.ByteString as BS
import qualified Text.Pandoc.UTF8 as UTF8
import System.IO.Unsafe (unsafePerformIO) -- TODO temporary
@@ -23,7 +24,7 @@ runTest :: String -- ^ Title of test
-> String -- ^ Expected output
-> TestTree
runTest testname cmd inp norm = testCase testname $ do
- let cmd' = cmd ++ " --quiet --data-dir ../data"
+ let cmd' = cmd ++ " --data-dir ../data"
let findDynlibDir [] = Nothing
findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
findDynlibDir (_:xs) = findDynlibDir xs
@@ -35,9 +36,9 @@ runTest testname cmd inp norm = testCase testname $ do
("LD_LIBRARY_PATH", d)]
let env' = dynlibEnv ++ [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./")]
let pr = (shell cmd'){ env = Just env' }
- (ec, out', _err) <- readCreateProcessWithExitCode pr inp
+ (ec, out', err') <- readCreateProcessWithExitCode pr inp
-- filter \r so the tests will work on Windows machines
- let out = filter (/= '\r') out'
+ let out = filter (/= '\r') $ err' ++ out'
result <- if ec == ExitSuccess
then do
if out == norm
@@ -83,7 +84,7 @@ runCommandTest pandocpath (num, code) =
extractCommandTest :: FilePath -> FilePath -> TestTree
extractCommandTest pandocpath fp = unsafePerformIO $ do
- contents <- UTF8.readFile ("command" </> fp)
+ contents <- UTF8.toText <$> BS.readFile ("command" </> fp)
Pandoc _ blocks <- runIOorExplode (readMarkdown
def{ readerExtensions = pandocExtensions } contents)
let codeblocks = map extractCode $ filter isCodeBlock $ blocks
diff --git a/test/Tests/Helpers.hs b/test/Tests/Helpers.hs
index 7e8ebb01a..2a6543ea0 100644
--- a/test/Tests/Helpers.hs
+++ b/test/Tests/Helpers.hs
@@ -15,6 +15,7 @@ module Tests.Helpers ( test
import Data.Algorithm.Diff
import qualified Data.Map as M
+import Data.Text (Text, unpack)
import System.Directory
import System.Environment.Executable (getExecutablePath)
import System.Exit
@@ -105,21 +106,25 @@ class ToString a where
toString :: a -> String
instance ToString Pandoc where
- toString d = purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ toString d = unpack $
+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
where s = case d of
(Pandoc (Meta m) _)
| M.null m -> Nothing
| otherwise -> Just "" -- need this to get meta output
instance ToString Blocks where
- toString = purely (writeNative def) . toPandoc
+ toString = unpack . purely (writeNative def) . toPandoc
instance ToString Inlines where
- toString = trimr . purely (writeNative def) . toPandoc
+ toString = trimr . unpack . purely (writeNative def) . toPandoc
instance ToString String where
toString = id
+instance ToString Text where
+ toString = unpack
+
class ToPandoc a where
toPandoc :: a -> Pandoc
diff --git a/test/Tests/Lua.hs b/test/Tests/Lua.hs
index 50f9634a2..cd8604ab9 100644
--- a/test/Tests/Lua.hs
+++ b/test/Tests/Lua.hs
@@ -3,9 +3,9 @@ module Tests.Lua ( tests ) where
import Control.Monad (when)
import System.FilePath ((</>))
-import Test.Tasty (TestTree)
+import Test.Tasty (TestTree, localOption)
import Test.Tasty.HUnit (Assertion, assertEqual, testCase)
-import Test.Tasty.QuickCheck (ioProperty, testProperty)
+import Test.Tasty.QuickCheck (ioProperty, testProperty, QuickCheckTests(..))
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Definition (Block, Inline, Meta, Pandoc)
import Text.Pandoc.Builder ( (<>), bulletList, doc, doubleQuoted, emph
@@ -16,7 +16,7 @@ import Text.Pandoc.Lua
import qualified Scripting.Lua as Lua
tests :: [TestTree]
-tests =
+tests = map (localOption (QuickCheckTests 20))
[ testProperty "inline elements can be round-tripped through the lua stack" $
\x -> ioProperty (roundtripEqual (x::Inline))
diff --git a/test/Tests/Readers/Docx.hs b/test/Tests/Readers/Docx.hs
index 028a4ff2f..e55c3529b 100644
--- a/test/Tests/Readers/Docx.hs
+++ b/test/Tests/Readers/Docx.hs
@@ -2,11 +2,14 @@ module Tests.Readers.Docx (tests) where
import Codec.Archive.Zip
import qualified Data.ByteString.Lazy as B
+import qualified Data.ByteString as BS
+import qualified Data.Text as T
import qualified Data.Map as M
import Test.Tasty
import Test.Tasty.HUnit
import Tests.Helpers
import Text.Pandoc
+import Text.Pandoc.UTF8 as UTF8
import qualified Text.Pandoc.Class as P
import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
import System.IO.Unsafe -- TODO temporary
@@ -25,7 +28,7 @@ defopts :: ReaderOptions
defopts = def{ readerExtensions = getDefaultExtensions "docx" }
instance ToString NoNormPandoc where
- toString d = purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ toString d = T.unpack $ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
where s = case d of
NoNormPandoc (Pandoc (Meta m) _)
| M.null m -> Nothing
@@ -40,7 +43,7 @@ compareOutput :: ReaderOptions
-> IO (NoNormPandoc, NoNormPandoc)
compareOutput opts docxFile nativeFile = do
df <- B.readFile docxFile
- nf <- Prelude.readFile nativeFile
+ nf <- UTF8.toText <$> BS.readFile nativeFile
p <- runIOorExplode $ readDocx opts df
df' <- runIOorExplode $ readNative def nf
return $ (noNorm p, noNorm df')
diff --git a/test/Tests/Readers/HTML.hs b/test/Tests/Readers/HTML.hs
index e2262d131..8647540b6 100644
--- a/test/Tests/Readers/HTML.hs
+++ b/test/Tests/Readers/HTML.hs
@@ -6,8 +6,9 @@ import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
+import Data.Text (Text)
-html :: String -> Pandoc
+html :: Text -> Pandoc
html = purely $ readHtml def
tests :: [TestTree]
diff --git a/test/Tests/Readers/LaTeX.hs b/test/Tests/Readers/LaTeX.hs
index 75547ed6b..afac9e8cb 100644
--- a/test/Tests/Readers/LaTeX.hs
+++ b/test/Tests/Readers/LaTeX.hs
@@ -6,14 +6,16 @@ import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
+import Data.Text (Text)
+import qualified Data.Text as T
-latex :: String -> Pandoc
+latex :: Text -> Pandoc
latex = purely $ readLaTeX def{
readerExtensions = getDefaultExtensions "latex" }
infix 4 =:
(=:) :: ToString c
- => String -> (String, c) -> TestTree
+ => String -> (Text, c) -> TestTree
(=:) = test latex
simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
@@ -74,7 +76,7 @@ tests = [ testGroup "basic"
"\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
, "Multi line table" =:
- unlines [ "\\begin{tabular}{|c|}"
+ T.unlines [ "\\begin{tabular}{|c|}"
, "One\\\\"
, "Two\\\\"
, "Three\\\\"
@@ -91,7 +93,7 @@ tests = [ testGroup "basic"
"\\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}"
+ T.unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
, "One&Two\\\\"
, "\\end{tabular}" ] =?>
simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
@@ -108,10 +110,10 @@ tests = [ testGroup "basic"
, let hex = ['0'..'9']++['a'..'f'] in
testGroup "Character Escapes"
[ "Two-character escapes" =:
- concat ["^^"++[i,j] | i <- hex, j <- hex] =?>
+ mconcat ["^^" <> T.pack [i,j] | i <- hex, j <- hex] =?>
para (str ['\0'..'\255'])
, "One-character escapes" =:
- concat ["^^"++[i] | i <- hex] =?>
+ mconcat ["^^" <> T.pack [i] | i <- hex] =?>
para (str $ ['p'..'y']++['!'..'&'])
]
]
diff --git a/test/Tests/Readers/Markdown.hs b/test/Tests/Readers/Markdown.hs
index e1d0c8e1f..1cd32b87d 100644
--- a/test/Tests/Readers/Markdown.hs
+++ b/test/Tests/Readers/Markdown.hs
@@ -1,38 +1,40 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Readers.Markdown (tests) where
+import Data.Text (Text, unpack)
+import qualified Data.Text as T
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
-markdown :: String -> Pandoc
+markdown :: Text -> Pandoc
markdown = purely $ readMarkdown def { readerExtensions =
disableExtension Ext_smart pandocExtensions }
-markdownSmart :: String -> Pandoc
+markdownSmart :: Text -> Pandoc
markdownSmart = purely $ readMarkdown def { readerExtensions =
enableExtension Ext_smart pandocExtensions }
-markdownCDL :: String -> Pandoc
+markdownCDL :: Text -> Pandoc
markdownCDL = purely $ readMarkdown def { readerExtensions = enableExtension
Ext_compact_definition_lists pandocExtensions }
-markdownGH :: String -> Pandoc
+markdownGH :: Text -> Pandoc
markdownGH = purely $ readMarkdown def {
readerExtensions = githubMarkdownExtensions }
infix 4 =:
(=:) :: ToString c
- => String -> (String, c) -> TestTree
+ => String -> (Text, c) -> TestTree
(=:) = test markdown
-testBareLink :: (String, Inlines) -> TestTree
+testBareLink :: (Text, Inlines) -> TestTree
testBareLink (inp, ils) =
test (purely $ readMarkdown def{ readerExtensions =
extensionsFromList [Ext_autolink_bare_uris, Ext_raw_html] })
- inp (inp, doc $ para ils)
+ (unpack inp) (inp, doc $ para ils)
autolink :: String -> Inlines
autolink = autolinkWith nullAttr
@@ -40,7 +42,7 @@ autolink = autolinkWith nullAttr
autolinkWith :: Attr -> String -> Inlines
autolinkWith attr s = linkWith attr s "" (str s)
-bareLinkTests :: [(String, Inlines)]
+bareLinkTests :: [(Text, Inlines)]
bareLinkTests =
[ ("http://google.com is a search engine.",
autolink "http://google.com" <> " is a search engine.")
@@ -376,10 +378,10 @@ tests = [ testGroup "inline code"
rawBlock "html" "</button>" <>
divWith nullAttr (para $ text "with this div too.")]
, test markdownGH "issue #1636" $
- unlines [ "* a"
- , "* b"
- , "* c"
- , " * d" ]
+ T.unlines [ "* a"
+ , "* b"
+ , "* c"
+ , " * d" ]
=?>
bulletList [ plain "a"
, plain "b"
@@ -419,9 +421,9 @@ tests = [ testGroup "inline code"
, let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita")
in testGroup "footnote/link following citation" -- issue #2083
[ "footnote" =:
- unlines [ "@cita[^note]"
- , ""
- , "[^note]: note" ] =?>
+ T.unlines [ "@cita[^note]"
+ , ""
+ , "[^note]: note" ] =?>
para (
citation <> note (para $ str "note")
)
@@ -431,22 +433,22 @@ tests = [ testGroup "inline code"
citation <> space <> link "http://www.com" "" (str "link")
)
, "reference link" =:
- unlines [ "@cita [link][link]"
- , ""
- , "[link]: http://www.com" ] =?>
+ T.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" ] =?>
+ T.unlines [ "@cita [link]"
+ , ""
+ , "[link]: http://www.com" ] =?>
para (
citation <> space <> link "http://www.com" "" (str "link")
)
, "implicit header link" =:
- unlines [ "# Header"
- , "@cita [Header]" ] =?>
+ T.unlines [ "# Header"
+ , "@cita [Header]" ] =?>
headerWith ("header",[],[]) 1 (str "Header") <> para (
citation <> space <> link "#header" "" (str "Header")
)
diff --git a/test/Tests/Readers/Odt.hs b/test/Tests/Readers/Odt.hs
index 6fc062158..eed3a33b0 100644
--- a/test/Tests/Readers/Odt.hs
+++ b/test/Tests/Readers/Odt.hs
@@ -2,7 +2,10 @@ module Tests.Readers.Odt (tests) where
import Control.Monad (liftM)
import qualified Data.ByteString.Lazy as B
+import qualified Data.ByteString as BS
+import qualified Text.Pandoc.UTF8 as UTF8
import qualified Data.Map as M
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -39,7 +42,8 @@ newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
deriving ( Show )
instance ToString NoNormPandoc where
- toString d = purely (writeNative def{ writerTemplate = s }) $ toPandoc d
+ toString d = unpack $
+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
where s = case d of
NoNormPandoc (Pandoc (Meta m) _)
| M.null m -> Nothing
@@ -58,7 +62,7 @@ type TestCreator = ReaderOptions
compareOdtToNative :: TestCreator
compareOdtToNative opts odtPath nativePath = do
- nativeFile <- Prelude.readFile nativePath
+ nativeFile <- UTF8.toText <$> BS.readFile nativePath
odtFile <- B.readFile odtPath
native <- getNoNormVia id "native" <$> runIO (readNative def nativeFile)
odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile)
@@ -66,7 +70,7 @@ compareOdtToNative opts odtPath nativePath = do
compareOdtToMarkdown :: TestCreator
compareOdtToMarkdown opts odtPath markdownPath = do
- markdownFile <- Prelude.readFile markdownPath
+ markdownFile <- UTF8.toText <$> BS.readFile markdownPath
odtFile <- B.readFile odtPath
markdown <- getNoNormVia id "markdown" <$>
runIO (readMarkdown def{ readerExtensions = pandocExtensions }
diff --git a/test/Tests/Readers/Org.hs b/test/Tests/Readers/Org.hs
index 7a7960396..45b10da42 100644
--- a/test/Tests/Readers/Org.hs
+++ b/test/Tests/Readers/Org.hs
@@ -2,21 +2,23 @@
module Tests.Readers.Org (tests) where
import Data.List (intersperse)
+import Data.Text (Text)
+import qualified Data.Text as T
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Builder
-org :: String -> Pandoc
+org :: Text -> Pandoc
org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" }
-orgSmart :: String -> Pandoc
+orgSmart :: Text -> Pandoc
orgSmart = purely $ readOrg def { readerExtensions =
enableExtension Ext_smart $ getDefaultExtensions "org" }
infix 4 =:
(=:) :: ToString c
- => String -> (String, c) -> TestTree
+ => String -> (Text, c) -> TestTree
(=:) = test org
spcSep :: [Inlines] -> Inlines
@@ -26,7 +28,11 @@ simpleTable' :: Int
-> [Blocks]
-> [[Blocks]]
-> Blocks
-simpleTable' n = table "" (take n $ repeat (AlignDefault, 0.0))
+simpleTable' n = table "" (replicate n (AlignDefault, 0.0))
+
+-- | Create a span for the given tag.
+tagSpan :: String -> Inlines
+tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) . smallcaps $ str t
tests :: [TestTree]
tests =
@@ -108,17 +114,17 @@ tests =
para (note $ para "Schreib mir eine E-Mail")
, "Markup-chars not occuring on word break are symbols" =:
- unlines [ "this+that+ +so+on"
- , "seven*eight* nine*"
- , "+not+funny+"
- ] =?>
+ T.unlines [ "this+that+ +so+on"
+ , "seven*eight* nine*"
+ , "+not+funny+"
+ ] =?>
para ("this+that+ +so+on" <> softbreak <>
"seven*eight* nine*" <> softbreak <>
strikeout "not+funny")
, "No empty markup" =:
- "// ** __ ++ == ~~ $$" =?>
- para (spcSep [ "//", "**", "__", "++", "==", "~~", "$$" ])
+ "// ** __ <> == ~~ $$" =?>
+ para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ])
, "Adherence to Org's rules for markup borders" =:
"/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
@@ -139,11 +145,11 @@ tests =
para "/nada,/"
, "Markup should work properly after a blank line" =:
- unlines ["foo", "", "/bar/"] =?>
+ T.unlines ["foo", "", "/bar/"] =?>
(para $ text "foo") <> (para $ emph $ text "bar")
, "Inline math must stay within three lines" =:
- unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
+ T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
para ((math "a\nb\nc") <> softbreak <>
"$d" <> softbreak <> "e" <> softbreak <>
"f" <> softbreak <> "g$")
@@ -165,17 +171,17 @@ tests =
softbreak <> "emph/")
, "Sub- and superscript expressions" =:
- unlines [ "a_(a(b)(c)d)"
- , "e^(f(g)h)"
- , "i_(jk)l)"
- , "m^()n"
- , "o_{p{q{}r}}"
- , "s^{t{u}v}"
- , "w_{xy}z}"
- , "1^{}2"
- , "3_{{}}"
- , "4^(a(*b(c*)d))"
- ] =?>
+ T.unlines [ "a_(a(b)(c)d)"
+ , "e^(f(g)h)"
+ , "i_(jk)l)"
+ , "m^()n"
+ , "o_{p{q{}r}}"
+ , "s^{t{u}v}"
+ , "w_{xy}z}"
+ , "1^{}2"
+ , "3_{{}}"
+ , "4^(a(*b(c*)d))"
+ ] =?>
para (mconcat $ intersperse softbreak
[ "a" <> subscript "(a(b)(c)d)"
, "e" <> superscript "(f(g)h)"
@@ -202,17 +208,17 @@ tests =
(para $ image "sunrise.jpg" "" "")
, "Multiple images within a paragraph" =:
- unlines [ "[[file:sunrise.jpg]]"
- , "[[file:sunset.jpg]]"
- ] =?>
+ T.unlines [ "[[file:sunrise.jpg]]"
+ , "[[file:sunset.jpg]]"
+ ] =?>
(para $ (image "sunrise.jpg" "" "")
<> softbreak
<> (image "sunset.jpg" "" ""))
, "Image with html attributes" =:
- unlines [ "#+ATTR_HTML: :width 50%"
- , "[[file:guinea-pig.gif]]"
- ] =?>
+ T.unlines [ "#+ATTR_HTML: :width 50%"
+ , "[[file:guinea-pig.gif]]"
+ ] =?>
(para $ imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
]
@@ -334,6 +340,18 @@ tests =
}
in (para $ cite [citation] "cite:pandoc")
+ , "Org-ref simple citation with underscores" =:
+ "cite:pandoc_org_ref" =?>
+ let citation = Citation
+ { citationId = "pandoc_org_ref"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc_org_ref")
+
, "Org-ref simple citation succeeded by comma" =:
"cite:pandoc," =?>
let citation = Citation
@@ -346,6 +364,30 @@ tests =
}
in (para $ cite [citation] "cite:pandoc" <> str ",")
+ , "Org-ref simple citation succeeded by dot" =:
+ "cite:pandoc." =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ".")
+
+ , "Org-ref simple citation succeeded by colon" =:
+ "cite:pandoc:" =?>
+ let citation = Citation
+ { citationId = "pandoc"
+ , citationPrefix = mempty
+ , citationSuffix = mempty
+ , citationMode = AuthorInText
+ , citationNoteNum = 0
+ , citationHash = 0
+ }
+ in (para $ cite [citation] "cite:pandoc" <> str ":")
+
, "Org-ref simple citep citation" =:
"citep:pandoc" =?>
let citation = Citation
@@ -469,6 +511,24 @@ tests =
, citationNoteNum = 0
, citationHash = 0}
in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
+
+ , "Macro" =:
+ T.unlines [ "#+MACRO: HELLO /Hello, $1/"
+ , "{{{HELLO(World)}}}"
+ ] =?>
+ para (emph "Hello, World")
+
+ , "Macro repeting its argument" =:
+ T.unlines [ "#+MACRO: HELLO $1$1"
+ , "{{{HELLO(moin)}}}"
+ ] =?>
+ para "moinmoin"
+
+ , "Macro called with too few arguments" =:
+ T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
+ , "{{{HELLO()}}}"
+ ] =?>
+ para "Foo Bar"
]
, testGroup "Meta Information" $
@@ -481,10 +541,10 @@ tests =
para "#-tag"
, "Comment surrounded by Text" =:
- unlines [ "Before"
- , "# Comment"
- , "After"
- ] =?>
+ T.unlines [ "Before"
+ , "# Comment"
+ , "After"
+ ] =?>
mconcat [ para "Before"
, para "After"
]
@@ -521,10 +581,10 @@ tests =
in Pandoc meta mempty
, "Properties drawer" =:
- unlines [ " :PROPERTIES:"
- , " :setting: foo"
- , " :END:"
- ] =?>
+ T.unlines [ " :PROPERTIES:"
+ , " :setting: foo"
+ , " :END:"
+ ] =?>
(mempty::Blocks)
, "LaTeX_headers options are translated to header-includes" =:
@@ -552,46 +612,46 @@ tests =
in Pandoc meta mempty
, "later meta definitions take precedence" =:
- unlines [ "#+AUTHOR: this will not be used"
- , "#+author: Max"
- ] =?>
+ T.unlines [ "#+AUTHOR: this will not be used"
+ , "#+author: Max"
+ ] =?>
let author = MetaInlines [Str "Max"]
meta = setMeta "author" (MetaList [author]) $ nullMeta
in Pandoc meta mempty
, "Logbook drawer" =:
- unlines [ " :LogBook:"
- , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
- , " :END:"
- ] =?>
+ T.unlines [ " :LogBook:"
+ , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
+ , " :END:"
+ ] =?>
(mempty::Blocks)
, "Drawer surrounded by text" =:
- unlines [ "Before"
- , ":PROPERTIES:"
- , ":END:"
- , "After"
- ] =?>
+ T.unlines [ "Before"
+ , ":PROPERTIES:"
+ , ":END:"
+ , "After"
+ ] =?>
para "Before" <> para "After"
, "Drawer markers must be the only text in the line" =:
- unlines [ " :LOGBOOK: foo"
- , " :END: bar"
- ] =?>
+ T.unlines [ " :LOGBOOK: foo"
+ , " :END: bar"
+ ] =?>
para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
, "Drawers can be arbitrary" =:
- unlines [ ":FOO:"
- , "/bar/"
- , ":END:"
- ] =?>
+ T.unlines [ ":FOO:"
+ , "/bar/"
+ , ":END:"
+ ] =?>
divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
, "Anchor reference" =:
- unlines [ "<<link-here>> Target."
- , ""
- , "[[link-here][See here!]]"
- ] =?>
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link-here][See here!]]"
+ ] =?>
(para (spanWith ("link-here", [], []) mempty <> "Target.") <>
para (link "#link-here" "" ("See" <> space <> "here!")))
@@ -600,129 +660,148 @@ tests =
(para (emph $ "Where's" <> space <> "Wally?"))
, "Link to nonexistent anchor" =:
- unlines [ "<<link-here>> Target."
- , ""
- , "[[link$here][See here!]]"
- ] =?>
+ T.unlines [ "<<link-here>> Target."
+ , ""
+ , "[[link$here][See here!]]"
+ ] =?>
(para (spanWith ("link-here", [], []) mempty <> "Target.") <>
para (emph ("See" <> space <> "here!")))
, "Link abbreviation" =:
- unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
- , "[[wp:Org_mode][Wikipedia on Org-mode]]"
- ] =?>
+ T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
+ , "[[wp:Org_mode][Wikipedia on Org-mode]]"
+ ] =?>
(para (link "https://en.wikipedia.org/wiki/Org_mode" ""
("Wikipedia" <> space <> "on" <> space <> "Org-mode")))
, "Link abbreviation, defined after first use" =:
- unlines [ "[[zl:non-sense][Non-sense articles]]"
- , "#+LINK: zl http://zeitlens.com/tags/%s.html"
- ] =?>
+ T.unlines [ "[[zl:non-sense][Non-sense articles]]"
+ , "#+LINK: zl http://zeitlens.com/tags/%s.html"
+ ] =?>
(para (link "http://zeitlens.com/tags/non-sense.html" ""
("Non-sense" <> space <> "articles")))
, "Link abbreviation, URL encoded arguments" =:
- unlines [ "#+link: expl http://example.com/%h/foo"
- , "[[expl:Hello, World!][Moin!]]"
- ] =?>
+ T.unlines [ "#+link: expl http://example.com/%h/foo"
+ , "[[expl:Hello, World!][Moin!]]"
+ ] =?>
(para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!"))
, "Link abbreviation, append arguments" =:
- unlines [ "#+link: expl http://example.com/"
- , "[[expl:foo][bar]]"
- ] =?>
+ T.unlines [ "#+link: expl http://example.com/"
+ , "[[expl:foo][bar]]"
+ ] =?>
(para (link "http://example.com/foo" "" "bar"))
, testGroup "export options"
[ "disable simple sub/superscript syntax" =:
- unlines [ "#+OPTIONS: ^:nil"
- , "a^b"
- ] =?>
+ T.unlines [ "#+OPTIONS: ^:nil"
+ , "a^b"
+ ] =?>
para "a^b"
, "directly select drawers to be exported" =:
- unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
- , ":IMPORTANT:"
- , "23"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
+ T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
+ , ":IMPORTANT:"
+ , "23"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
, "exclude drawers from being exported" =:
- unlines [ "#+OPTIONS: d:(not \"BORING\")"
- , ":IMPORTANT:"
- , "5"
- , ":END:"
- , ":BORING:"
- , "very boring"
- , ":END:"
- ] =?>
+ T.unlines [ "#+OPTIONS: d:(not \"BORING\")"
+ , ":IMPORTANT:"
+ , "5"
+ , ":END:"
+ , ":BORING:"
+ , "very boring"
+ , ":END:"
+ ] =?>
divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
, "don't include archive trees" =:
- unlines [ "#+OPTIONS: arch:nil"
- , "* old :ARCHIVE:"
- ] =?>
+ T.unlines [ "#+OPTIONS: arch:nil"
+ , "* old :ARCHIVE:"
+ ] =?>
(mempty ::Blocks)
, "include complete archive trees" =:
- unlines [ "#+OPTIONS: arch:t"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in mconcat [ headerWith ("old", [], mempty) 1 ("old" <> tagSpan "ARCHIVE")
- , para "boring"
- ]
+ T.unlines [ "#+OPTIONS: arch:t"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ mconcat [ headerWith ("old", [], mempty) 1
+ ("old" <> space <> tagSpan "ARCHIVE")
+ , para "boring"
+ ]
, "include archive tree header only" =:
- unlines [ "#+OPTIONS: arch:headline"
- , "* old :ARCHIVE:"
- , " boring"
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in headerWith ("old", [], mempty) 1 ("old" <> tagSpan "ARCHIVE")
+ T.unlines [ "#+OPTIONS: arch:headline"
+ , "* old :ARCHIVE:"
+ , " boring"
+ ] =?>
+ headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE")
, "limit headline depth" =:
- unlines [ "#+OPTIONS: H:2"
- , "* section"
- , "** subsection"
- , "*** list item 1"
- , "*** list item 2"
- ] =?>
- mconcat [ headerWith ("section", [], []) 1 "section"
+ T.unlines [ "#+OPTIONS: H:2"
+ , "* top-level section"
+ , "** subsection"
+ , "*** list item 1"
+ , "*** list item 2"
+ ] =?>
+ mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section"
, headerWith ("subsection", [], []) 2 "subsection"
, orderedList [ para "list item 1", para "list item 2" ]
]
+ , "turn all headlines into lists" =:
+ T.unlines [ "#+OPTIONS: H:0"
+ , "first block"
+ , "* top-level section 1"
+ , "** subsection"
+ , "* top-level section 2"
+ ] =?>
+ mconcat [ para "first block"
+ , orderedList
+ [ (para "top-level section 1" <>
+ orderedList [ para "subsection" ])
+ , para "top-level section 2" ]
+ ]
+
, "disable author export" =:
- unlines [ "#+OPTIONS: author:nil"
- , "#+AUTHOR: ShyGuy"
- ] =?>
+ T.unlines [ "#+OPTIONS: author:nil"
+ , "#+AUTHOR: ShyGuy"
+ ] =?>
Pandoc nullMeta mempty
, "disable creator export" =:
- unlines [ "#+OPTIONS: creator:nil"
- , "#+creator: The Architect"
- ] =?>
+ T.unlines [ "#+OPTIONS: creator:nil"
+ , "#+creator: The Architect"
+ ] =?>
Pandoc nullMeta mempty
, "disable email export" =:
- unlines [ "#+OPTIONS: email:nil"
- , "#+email: no-mail-please@example.com"
- ] =?>
+ T.unlines [ "#+OPTIONS: email:nil"
+ , "#+email: no-mail-please@example.com"
+ ] =?>
Pandoc nullMeta mempty
, "disable inclusion of todo keywords" =:
- unlines [ "#+OPTIONS: todo:nil"
- , "** DONE todo export"
- ] =?>
+ T.unlines [ "#+OPTIONS: todo:nil"
+ , "** DONE todo export"
+ ] =?>
headerWith ("todo-export", [], []) 2 "todo export"
+
+ , "remove tags from headlines" =:
+ T.unlines [ "#+OPTIONS: tags:nil"
+ , "* Headline :hello:world:"
+ ] =?>
+ headerWith ("headline", [], mempty) 1 "Headline"
]
]
@@ -743,10 +822,10 @@ tests =
("Third" <> space <> "Level" <> space <> "Headline")
, "Compact Headers with Paragraph" =:
- unlines [ "* First Level"
- , "** Second Level"
- , " Text"
- ] =?>
+ T.unlines [ "* First Level"
+ , "** Second Level"
+ , " Text"
+ ] =?>
mconcat [ headerWith ("first-level", [], [])
1
("First" <> space <> "Level")
@@ -757,12 +836,12 @@ tests =
]
, "Separated Headers with Paragraph" =:
- unlines [ "* First Level"
- , ""
- , "** Second Level"
- , ""
- , " Text"
- ] =?>
+ T.unlines [ "* First Level"
+ , ""
+ , "** Second Level"
+ , ""
+ , " Text"
+ ] =?>
mconcat [ headerWith ("first-level", [], [])
1
("First" <> space <> "Level")
@@ -773,10 +852,10 @@ tests =
]
, "Headers not preceded by a blank line" =:
- unlines [ "** eat dinner"
- , "Spaghetti and meatballs tonight."
- , "** walk dog"
- ] =?>
+ T.unlines [ "** eat dinner"
+ , "Spaghetti and meatballs tonight."
+ , "** walk dog"
+ ] =?>
mconcat [ headerWith ("eat-dinner", [], [])
2
("eat" <> space <> "dinner")
@@ -802,21 +881,21 @@ tests =
headerWith ("waiting-header", [], []) 1 "WAITING header"
, "Custom todo keywords" =:
- unlines [ "#+TODO: WAITING CANCELLED"
- , "* WAITING compile"
- , "* CANCELLED lunch"
- ] =?>
+ T.unlines [ "#+TODO: WAITING CANCELLED"
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ ] =?>
let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
<> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
, "Custom todo keywords with multiple done-states" =:
- unlines [ "#+TODO: WAITING | DONE CANCELLED "
- , "* WAITING compile"
- , "* CANCELLED lunch"
- , "* DONE todo-feature"
- ] =?>
+ T.unlines [ "#+TODO: WAITING | DONE CANCELLED "
+ , "* WAITING compile"
+ , "* CANCELLED lunch"
+ , "* DONE todo-feature"
+ ] =?>
let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
done = spanWith ("", ["done", "DONE"], []) "DONE"
@@ -826,31 +905,30 @@ tests =
]
, "Tagged headers" =:
- unlines [ "* Personal :PERSONAL:"
- , "** Call Mom :@PHONE:"
- , "** Call John :@PHONE:JOHN: "
- ] =?>
- let tagSpan t = spanWith ("", ["tag"], [("data-tag-name", t)]) mempty
- in mconcat [ headerWith ("personal", [], [])
- 1
- ("Personal" <> tagSpan "PERSONAL")
- , headerWith ("call-mom", [], [])
- 2
- ("Call Mom" <> tagSpan "@PHONE")
- , headerWith ("call-john", [], [])
- 2
- ("Call John" <> tagSpan "@PHONE" <> tagSpan "JOHN")
- ]
+ T.unlines [ "* Personal :PERSONAL:"
+ , "** Call Mom :@PHONE:"
+ , "** Call John :@PHONE:JOHN: "
+ ] =?>
+ mconcat [ headerWith ("personal", [], [])
+ 1
+ ("Personal " <> tagSpan "PERSONAL")
+ , headerWith ("call-mom", [], [])
+ 2
+ ("Call Mom " <> tagSpan "@PHONE")
+ , headerWith ("call-john", [], [])
+ 2
+ ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN")
+ ]
, "Untagged header containing colons" =:
"* This: is not: tagged" =?>
headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
, "Header starting with strokeout text" =:
- unlines [ "foo"
- , ""
- , "* +thing+ other thing"
- ] =?>
+ T.unlines [ "foo"
+ , ""
+ , "* +thing+ other thing"
+ ] =?>
mconcat [ para "foo"
, headerWith ("thing-other-thing", [], [])
1
@@ -858,11 +936,11 @@ tests =
]
, "Comment Trees" =:
- unlines [ "* COMMENT A comment tree"
- , " Not much going on here"
- , "** This will be dropped"
- , "* Comment tree above"
- ] =?>
+ T.unlines [ "* COMMENT A comment tree"
+ , " Not much going on here"
+ , "** This will be dropped"
+ , "* Comment tree above"
+ ] =?>
headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
, "Nothing but a COMMENT header" =:
@@ -870,38 +948,38 @@ tests =
(mempty::Blocks)
, "Tree with :noexport:" =:
- unlines [ "* Should be ignored :archive:noexport:old:"
- , "** Old stuff"
- , " This is not going to be exported"
- ] =?>
+ T.unlines [ "* Should be ignored :archive:noexport:old:"
+ , "** Old stuff"
+ , " This is not going to be exported"
+ ] =?>
(mempty::Blocks)
, "Subtree with :noexport:" =:
- unlines [ "* Exported"
- , "** This isn't exported :noexport:"
- , "*** This neither"
- , "** But this is"
- ] =?>
+ T.unlines [ "* Exported"
+ , "** This isn't exported :noexport:"
+ , "*** This neither"
+ , "** But this is"
+ ] =?>
mconcat [ headerWith ("exported", [], []) 1 "Exported"
, headerWith ("but-this-is", [], []) 2 "But this is"
]
, "Preferences are treated as header attributes" =:
- unlines [ "* foo"
- , " :PROPERTIES:"
- , " :custom_id: fubar"
- , " :bar: baz"
- , " :END:"
- ] =?>
+ T.unlines [ "* foo"
+ , " :PROPERTIES:"
+ , " :custom_id: fubar"
+ , " :bar: baz"
+ , " :END:"
+ ] =?>
headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
, "Headers marked with a unnumbered property get a class of the same name" =:
- unlines [ "* Not numbered"
- , " :PROPERTIES:"
- , " :UNNUMBERED: t"
- , " :END:"
- ] =?>
+ T.unlines [ "* Not numbered"
+ , " :PROPERTIES:"
+ , " :UNNUMBERED: t"
+ , " :END:"
+ ] =?>
headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
]
, "Paragraph starting with an asterisk" =:
@@ -909,23 +987,23 @@ tests =
para "*five"
, "Paragraph containing asterisk at beginning of line" =:
- unlines [ "lucky"
- , "*star"
- ] =?>
+ T.unlines [ "lucky"
+ , "*star"
+ ] =?>
para ("lucky" <> softbreak <> "*star")
, "Example block" =:
- unlines [ ": echo hello"
- , ": echo dear tester"
- ] =?>
+ T.unlines [ ": echo hello"
+ , ": echo dear tester"
+ ] =?>
codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
, "Example block surrounded by text" =:
- unlines [ "Greetings"
- , ": echo hello"
- , ": echo dear tester"
- , "Bye"
- ] =?>
+ T.unlines [ "Greetings"
+ , ": echo hello"
+ , ": echo dear tester"
+ , "Bye"
+ ] =?>
mconcat [ para "Greetings"
, codeBlockWith ("", ["example"], [])
"echo hello\necho dear tester\n"
@@ -933,81 +1011,81 @@ tests =
]
, "Horizontal Rule" =:
- unlines [ "before"
- , "-----"
- , "after"
- ] =?>
+ T.unlines [ "before"
+ , "-----"
+ , "after"
+ ] =?>
mconcat [ para "before"
, horizontalRule
, para "after"
]
, "Not a Horizontal Rule" =:
- "----- five dashes" =?>
- (para $ spcSep [ "-----", "five", "dashes" ])
+ "----- em and en dash" =?>
+ para "\8212\8211 em and en dash"
, "Comment Block" =:
- unlines [ "#+BEGIN_COMMENT"
- , "stuff"
- , "bla"
- , "#+END_COMMENT"] =?>
+ T.unlines [ "#+BEGIN_COMMENT"
+ , "stuff"
+ , "bla"
+ , "#+END_COMMENT"] =?>
(mempty::Blocks)
, testGroup "Figures" $
[ "Figure" =:
- unlines [ "#+caption: A very courageous man."
- , "#+name: goodguy"
- , "[[file:edward.jpg]]"
- ] =?>
+ T.unlines [ "#+caption: A very courageous man."
+ , "#+name: goodguy"
+ , "[[file:edward.jpg]]"
+ ] =?>
para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
, "Figure with no name" =:
- unlines [ "#+caption: I've been through the desert on this"
- , "[[file:horse.png]]"
- ] =?>
+ T.unlines [ "#+caption: I've been through the desert on this"
+ , "[[file:horse.png]]"
+ ] =?>
para (image "horse.png" "fig:" "I've been through the desert on this")
, "Figure with `fig:` prefix in name" =:
- unlines [ "#+caption: Used as a metapher in evolutionary biology."
- , "#+name: fig:redqueen"
- , "[[./the-red-queen.jpg]]"
- ] =?>
+ T.unlines [ "#+caption: Used as a metapher in evolutionary biology."
+ , "#+name: fig:redqueen"
+ , "[[./the-red-queen.jpg]]"
+ ] =?>
para (image "./the-red-queen.jpg" "fig:redqueen"
"Used as a metapher in evolutionary biology.")
, "Figure with HTML attributes" =:
- unlines [ "#+CAPTION: mah brain just explodid"
- , "#+NAME: lambdacat"
- , "#+ATTR_HTML: :style color: blue :role button"
- , "[[file:lambdacat.jpg]]"
- ] =?>
+ T.unlines [ "#+CAPTION: mah brain just explodid"
+ , "#+NAME: lambdacat"
+ , "#+ATTR_HTML: :style color: blue :role button"
+ , "[[file:lambdacat.jpg]]"
+ ] =?>
let kv = [("style", "color: blue"), ("role", "button")]
name = "fig:lambdacat"
caption = "mah brain just explodid"
in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
, "Labelled figure" =:
- unlines [ "#+CAPTION: My figure"
- , "#+LABEL: fig:myfig"
- , "[[file:blub.png]]"
- ] =?>
+ T.unlines [ "#+CAPTION: My figure"
+ , "#+LABEL: fig:myfig"
+ , "[[file:blub.png]]"
+ ] =?>
let attr = ("fig:myfig", mempty, mempty)
in para (imageWith attr "blub.png" "fig:" "My figure")
, "Figure with empty caption" =:
- unlines [ "#+CAPTION:"
- , "[[file:guess.jpg]]"
- ] =?>
+ T.unlines [ "#+CAPTION:"
+ , "[[file:guess.jpg]]"
+ ] =?>
para (image "guess.jpg" "fig:" "")
]
, "Footnote" =:
- unlines [ "A footnote[1]"
- , ""
- , "[1] First paragraph"
- , ""
- , "second paragraph"
- ] =?>
+ T.unlines [ "A footnote[1]"
+ , ""
+ , "[1] First paragraph"
+ , ""
+ , "second paragraph"
+ ] =?>
para (mconcat
[ "A", space, "footnote"
, note $ mconcat [ para ("First" <> space <> "paragraph")
@@ -1016,12 +1094,12 @@ tests =
])
, "Two footnotes" =:
- unlines [ "Footnotes[fn:1][fn:2]"
- , ""
- , "[fn:1] First note."
- , ""
- , "[fn:2] Second note."
- ] =?>
+ T.unlines [ "Footnotes[fn:1][fn:2]"
+ , ""
+ , "[fn:1] First note."
+ , ""
+ , "[fn:2] Second note."
+ ] =?>
para (mconcat
[ "Footnotes"
, note $ para ("First" <> space <> "note.")
@@ -1029,32 +1107,32 @@ tests =
])
, "Emphasized text before footnote" =:
- unlines [ "/text/[fn:1]"
- , ""
- , "[fn:1] unicorn"
- ] =?>
+ T.unlines [ "/text/[fn:1]"
+ , ""
+ , "[fn:1] unicorn"
+ ] =?>
para (mconcat
[ emph "text"
, note . para $ "unicorn"
])
, "Footnote that starts with emphasized text" =:
- unlines [ "text[fn:1]"
- , ""
- , "[fn:1] /emphasized/"
- ] =?>
+ T.unlines [ "text[fn:1]"
+ , ""
+ , "[fn:1] /emphasized/"
+ ] =?>
para (mconcat
[ "text"
, note . para $ emph "emphasized"
])
, "Footnote followed by header" =:
- unlines [ "Another note[fn:yay]"
- , ""
- , "[fn:yay] This is great!"
- , ""
- , "** Headline"
- ] =?>
+ T.unlines [ "Another note[fn:yay]"
+ , ""
+ , "[fn:yay] This is great!"
+ , ""
+ , "** Headline"
+ ] =?>
mconcat
[ para (mconcat
[ "Another", space, "note"
@@ -1066,43 +1144,43 @@ tests =
, testGroup "Lists" $
[ "Simple Bullet Lists" =:
- ("- Item1\n" ++
+ ("- Item1\n" <>
"- Item2\n") =?>
bulletList [ plain "Item1"
, plain "Item2"
]
, "Indented Bullet Lists" =:
- (" - Item1\n" ++
+ (" - Item1\n" <>
" - Item2\n") =?>
bulletList [ plain "Item1"
, plain "Item2"
]
, "Unindented *" =:
- ("- Item1\n" ++
+ ("- Item1\n" <>
"* Item2\n") =?>
bulletList [ plain "Item1"
] <>
headerWith ("item2", [], []) 1 "Item2"
, "Multi-line Bullet Lists" =:
- ("- *Fat\n" ++
- " Tony*\n" ++
- "- /Sideshow\n" ++
+ ("- *Fat\n" <>
+ " Tony*\n" <>
+ "- /Sideshow\n" <>
" Bob/") =?>
bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
, plain $ emph ("Sideshow" <> softbreak <> "Bob")
]
, "Nested Bullet Lists" =:
- ("- Discovery\n" ++
- " + One More Time\n" ++
- " + Harder, Better, Faster, Stronger\n" ++
- "- Homework\n" ++
- " + Around the World\n"++
- "- Human After All\n" ++
- " + Technologic\n" ++
+ ("- Discovery\n" <>
+ " + One More Time\n" <>
+ " + Harder, Better, Faster, Stronger\n" <>
+ "- Homework\n" <>
+ " + Around the World\n"<>
+ "- Human After All\n" <>
+ " + Technologic\n" <>
" + Robot Rock\n") =?>
bulletList [ mconcat
[ plain "Discovery"
@@ -1158,7 +1236,7 @@ tests =
]
, "Simple Ordered List" =:
- ("1. Item1\n" ++
+ ("1. Item1\n" <>
"2. Item2\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ plain "Item1"
@@ -1167,7 +1245,7 @@ tests =
in orderedListWith listStyle listStructure
, "Simple Ordered List with Parens" =:
- ("1) Item1\n" ++
+ ("1) Item1\n" <>
"2) Item2\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ plain "Item1"
@@ -1176,7 +1254,7 @@ tests =
in orderedListWith listStyle listStructure
, "Indented Ordered List" =:
- (" 1. Item1\n" ++
+ (" 1. Item1\n" <>
" 2. Item2\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ plain "Item1"
@@ -1185,11 +1263,11 @@ tests =
in orderedListWith listStyle listStructure
, "Nested Ordered Lists" =:
- ("1. One\n" ++
- " 1. One-One\n" ++
- " 2. One-Two\n" ++
- "2. Two\n" ++
- " 1. Two-One\n"++
+ ("1. One\n" <>
+ " 1. One-One\n" <>
+ " 2. One-Two\n" <>
+ "2. Two\n" <>
+ " 1. Two-One\n"<>
" 2. Two-Two\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ mconcat
@@ -1208,25 +1286,25 @@ tests =
in orderedListWith listStyle listStructure
, "Ordered List in Bullet List" =:
- ("- Emacs\n" ++
+ ("- Emacs\n" <>
" 1. Org\n") =?>
bulletList [ (plain "Emacs") <>
(orderedList [ plain "Org"])
]
, "Bullet List in Ordered List" =:
- ("1. GNU\n" ++
+ ("1. GNU\n" <>
" - Freedom\n") =?>
orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
, "Definition List" =:
- unlines [ "- PLL :: phase-locked loop"
- , "- TTL ::"
- , " transistor-transistor logic"
- , "- PSK :: phase-shift keying"
- , ""
- , " a digital modulation scheme"
- ] =?>
+ T.unlines [ "- PLL :: phase-locked loop"
+ , "- TTL ::"
+ , " transistor-transistor logic"
+ , "- PSK :: phase-shift keying"
+ , ""
+ , " a digital modulation scheme"
+ ] =?>
definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
, ("TTL", [ plain $ "transistor-transistor" <> space <>
"logic" ])
@@ -1241,11 +1319,11 @@ tests =
" - Elijah Wood :: He plays Frodo" =?>
definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
, "Compact definition list" =:
- unlines [ "- ATP :: adenosine 5' triphosphate"
- , "- DNA :: deoxyribonucleic acid"
- , "- PCR :: polymerase chain reaction"
- , ""
- ] =?>
+ T.unlines [ "- ATP :: adenosine 5' triphosphate"
+ , "- DNA :: deoxyribonucleic acid"
+ , "- PCR :: polymerase chain reaction"
+ , ""
+ ] =?>
definitionList
[ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
, ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
@@ -1267,21 +1345,21 @@ tests =
bulletList [ plain "std::cout" ]
, "Loose bullet list" =:
- unlines [ "- apple"
- , ""
- , "- orange"
- , ""
- , "- peach"
- ] =?>
+ T.unlines [ "- apple"
+ , ""
+ , "- orange"
+ , ""
+ , "- peach"
+ ] =?>
bulletList [ para "apple"
, para "orange"
, para "peach"
]
, "Recognize preceding paragraphs in non-list contexts" =:
- unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
- , "- Note taken on [2015-10-19 Mon 13:24]"
- ] =?>
+ T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
+ , "- Note taken on [2015-10-19 Mon 13:24]"
+ ] =?>
mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
, bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
]
@@ -1297,10 +1375,10 @@ tests =
simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
, "Multi line table" =:
- unlines [ "| One |"
- , "| Two |"
- , "| Three |"
- ] =?>
+ T.unlines [ "| One |"
+ , "| Two |"
+ , "| Three |"
+ ] =?>
simpleTable' 1 mempty
[ [ plain "One" ]
, [ plain "Two" ]
@@ -1312,10 +1390,10 @@ tests =
simpleTable' 1 mempty [[mempty]]
, "Glider Table" =:
- unlines [ "| 1 | 0 | 0 |"
- , "| 0 | 1 | 1 |"
- , "| 1 | 1 | 0 |"
- ] =?>
+ T.unlines [ "| 1 | 0 | 0 |"
+ , "| 0 | 1 | 1 |"
+ , "| 1 | 1 | 0 |"
+ ] =?>
simpleTable' 3 mempty
[ [ plain "1", plain "0", plain "0" ]
, [ plain "0", plain "1", plain "1" ]
@@ -1323,42 +1401,42 @@ tests =
]
, "Table between Paragraphs" =:
- unlines [ "Before"
- , "| One | Two |"
- , "After"
- ] =?>
+ T.unlines [ "Before"
+ , "| One | Two |"
+ , "After"
+ ] =?>
mconcat [ para "Before"
, simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
, para "After"
]
, "Table with Header" =:
- unlines [ "| Species | Status |"
- , "|--------------+--------------|"
- , "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- ] =?>
+ T.unlines [ "| Species | Status |"
+ , "|--------------+--------------|"
+ , "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ ] =?>
simpleTable [ plain "Species", plain "Status" ]
[ [ plain "cervisiae", plain "domesticated" ]
, [ plain "paradoxus", plain "wild" ]
]
, "Table with final hline" =:
- unlines [ "| cervisiae | domesticated |"
- , "| paradoxus | wild |"
- , "|--------------+--------------|"
- ] =?>
+ T.unlines [ "| cervisiae | domesticated |"
+ , "| paradoxus | wild |"
+ , "|--------------+--------------|"
+ ] =?>
simpleTable' 2 mempty
[ [ plain "cervisiae", plain "domesticated" ]
, [ plain "paradoxus", plain "wild" ]
]
, "Table in a box" =:
- unlines [ "|---------|---------|"
- , "| static | Haskell |"
- , "| dynamic | Lisp |"
- , "|---------+---------|"
- ] =?>
+ T.unlines [ "|---------|---------|"
+ , "| static | Haskell |"
+ , "| dynamic | Lisp |"
+ , "|---------+---------|"
+ ] =?>
simpleTable' 2 mempty
[ [ plain "static", plain "Haskell" ]
, [ plain "dynamic", plain "Lisp" ]
@@ -1369,18 +1447,18 @@ tests =
simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
, "Table with empty rows" =:
- unlines [ "| first |"
- , "| |"
- , "| third |"
- ] =?>
+ T.unlines [ "| first |"
+ , "| |"
+ , "| third |"
+ ] =?>
simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
, "Table with alignment row" =:
- unlines [ "| Numbers | Text | More |"
- , "| <c> | <r> | |"
- , "| 1 | One | foo |"
- , "| 2 | Two | bar |"
- ] =?>
+ T.unlines [ "| Numbers | Text | More |"
+ , "| <c> | <r> | |"
+ , "| 1 | One | foo |"
+ , "| 2 | Two | bar |"
+ ] =?>
table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
[]
[ [ plain "Numbers", plain "Text", plain "More" ]
@@ -1397,12 +1475,12 @@ tests =
simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
, "Table with differing row lengths" =:
- unlines [ "| Numbers | Text "
- , "|-"
- , "| <c> | <r> |"
- , "| 1 | One | foo |"
- , "| 2"
- ] =?>
+ T.unlines [ "| Numbers | Text "
+ , "|-"
+ , "| <c> | <r> |"
+ , "| 1 | One | foo |"
+ , "| 2"
+ ] =?>
table "" (zip [AlignCenter, AlignRight] [0, 0])
[ plain "Numbers", plain "Text" ]
[ [ plain "1" , plain "One" , plain "foo" ]
@@ -1410,10 +1488,10 @@ tests =
]
, "Table with caption" =:
- unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
- , "| x | 6 |"
- , "| 9 | 42 |"
- ] =?>
+ T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
+ , "| x | 6 |"
+ , "| 9 | 42 |"
+ ] =?>
table "Hitchhiker's Multiplication Table"
[(AlignDefault, 0), (AlignDefault, 0)]
[]
@@ -1424,59 +1502,59 @@ tests =
, testGroup "Blocks and fragments"
[ "Source block" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
+ code' = "main = putStrLn greeting\n" <>
" where greeting = \"moin\"\n"
in codeBlockWith attr' code'
, "Source block with indented code" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"moin\""
- , " #+END_SRC" ] =?>
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"moin\""
+ , " #+END_SRC" ] =?>
let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
+ code' = "main = putStrLn greeting\n" <>
" where greeting = \"moin\"\n"
in codeBlockWith attr' code'
, "Source block with tab-indented code" =:
- unlines [ "\t#+BEGIN_SRC haskell"
- , "\tmain = putStrLn greeting"
- , "\t where greeting = \"moin\""
- , "\t#+END_SRC" ] =?>
+ T.unlines [ "\t#+BEGIN_SRC haskell"
+ , "\tmain = putStrLn greeting"
+ , "\t where greeting = \"moin\""
+ , "\t#+END_SRC" ] =?>
let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
+ code' = "main = putStrLn greeting\n" <>
" where greeting = \"moin\"\n"
in codeBlockWith attr' code'
, "Empty source block" =:
- unlines [ " #+BEGIN_SRC haskell"
- , " #+END_SRC" ] =?>
+ T.unlines [ " #+BEGIN_SRC haskell"
+ , " #+END_SRC" ] =?>
let attr' = ("", ["haskell"], [])
code' = ""
in codeBlockWith attr' code'
, "Source block between paragraphs" =:
- unlines [ "Low German greeting"
- , " #+BEGIN_SRC haskell"
- , " main = putStrLn greeting"
- , " where greeting = \"Moin!\""
- , " #+END_SRC" ] =?>
+ T.unlines [ "Low German greeting"
+ , " #+BEGIN_SRC haskell"
+ , " main = putStrLn greeting"
+ , " where greeting = \"Moin!\""
+ , " #+END_SRC" ] =?>
let attr' = ("", ["haskell"], [])
- code' = "main = putStrLn greeting\n" ++
+ code' = "main = putStrLn greeting\n" <>
" where greeting = \"Moin!\"\n"
in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
, codeBlockWith attr' code'
]
, "Source block with babel arguments" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC" ] =?>
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC" ] =?>
let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax
params = [ ("data-org-language", "emacs-lisp")
, ("exports", "both")
@@ -1486,13 +1564,13 @@ tests =
in codeBlockWith ("", classes, params) code'
, "Source block with results and :exports both" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65"] =?>
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65"] =?>
let classes = [ "commonlisp" ]
params = [ ("data-org-language", "emacs-lisp")
, ("exports", "both")
@@ -1505,13 +1583,13 @@ tests =
codeBlockWith ("", ["example"], []) results'
, "Source block with results and :exports code" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
let classes = [ "commonlisp" ]
params = [ ("data-org-language", "emacs-lisp")
, ("exports", "code")
@@ -1521,87 +1599,87 @@ tests =
in codeBlockWith ("", classes, params) code'
, "Source block with results and :exports results" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
let results' = "65\n"
in codeBlockWith ("", ["example"], []) results'
, "Source block with results and :exports none" =:
- unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
- , "(progn (message \"Hello, World!\")"
- , " (+ 23 42))"
- , "#+END_SRC"
- , ""
- , "#+RESULTS:"
- , ": 65" ] =?>
+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
+ , "(progn (message \"Hello, World!\")"
+ , " (+ 23 42))"
+ , "#+END_SRC"
+ , ""
+ , "#+RESULTS:"
+ , ": 65" ] =?>
(mempty :: Blocks)
, "Source block with toggling header arguments" =:
- unlines [ "#+BEGIN_SRC sh :noeval"
- , "echo $HOME"
- , "#+END_SRC"
- ] =?>
+ T.unlines [ "#+BEGIN_SRC sh :noeval"
+ , "echo $HOME"
+ , "#+END_SRC"
+ ] =?>
let classes = [ "bash" ]
params = [ ("data-org-language", "sh"), ("noeval", "yes") ]
in codeBlockWith ("", classes, params) "echo $HOME\n"
, "Source block with line number switch" =:
- unlines [ "#+BEGIN_SRC sh -n 10"
- , ":() { :|:& };:"
- , "#+END_SRC"
- ] =?>
+ T.unlines [ "#+BEGIN_SRC sh -n 10"
+ , ":() { :|:& };:"
+ , "#+END_SRC"
+ ] =?>
let classes = [ "bash", "numberLines" ]
params = [ ("data-org-language", "sh"), ("startFrom", "10") ]
in codeBlockWith ("", classes, params) ":() { :|:& };:\n"
, "Source block with multi-word parameter values" =:
- unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
- , "digraph { id [label=\"ID\"] }"
- , "#+END_SRC"
- ] =?>
+ T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
+ , "digraph { id [label=\"ID\"] }"
+ , "#+END_SRC"
+ ] =?>
let classes = [ "dot" ]
params = [ ("cmdline", "-Kdot -Tpng") ]
in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n"
, "Example block" =:
- unlines [ "#+begin_example"
- , "A chosen representation of"
- , "a rule."
- , "#+eND_exAMPle"
- ] =?>
+ T.unlines [ "#+begin_example"
+ , "A chosen representation of"
+ , "a rule."
+ , "#+eND_exAMPle"
+ ] =?>
codeBlockWith ("", ["example"], [])
"A chosen representation of\na rule.\n"
, "HTML block" =:
- unlines [ "#+BEGIN_HTML"
- , "<aside>HTML5 is pretty nice.</aside>"
- , "#+END_HTML"
- ] =?>
+ T.unlines [ "#+BEGIN_HTML"
+ , "<aside>HTML5 is pretty nice.</aside>"
+ , "#+END_HTML"
+ ] =?>
rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
, "Quote block" =:
- unlines [ "#+BEGIN_QUOTE"
- , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
- , "#+END_QUOTE"
- ] =?>
+ T.unlines [ "#+BEGIN_QUOTE"
+ , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
+ , "#+END_QUOTE"
+ ] =?>
blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
, "eine", "Mauer", "zu", "errichten!"
]))
, "Verse block" =:
- unlines [ "The first lines of Goethe's /Faust/:"
- , "#+begin_verse"
- , "Habe nun, ach! Philosophie,"
- , "Juristerei und Medizin,"
- , "Und leider auch Theologie!"
- , "Durchaus studiert, mit heißem Bemühn."
- , "#+end_verse"
- ] =?>
+ T.unlines [ "The first lines of Goethe's /Faust/:"
+ , "#+begin_verse"
+ , "Habe nun, ach! Philosophie,"
+ , "Juristerei und Medizin,"
+ , "Und leider auch Theologie!"
+ , "Durchaus studiert, mit heißem Bemühn."
+ , "#+end_verse"
+ ] =?>
mconcat
[ para $ spcSep [ "The", "first", "lines", "of"
, "Goethe's", emph "Faust" <> ":"]
@@ -1614,27 +1692,27 @@ tests =
]
, "Verse block with blank lines" =:
- unlines [ "#+BEGIN_VERSE"
- , "foo"
- , ""
- , "bar"
- , "#+END_VERSE"
- ] =?>
+ T.unlines [ "#+BEGIN_VERSE"
+ , "foo"
+ , ""
+ , "bar"
+ , "#+END_VERSE"
+ ] =?>
lineBlock [ "foo", mempty, "bar" ]
, "Verse block with varying indentation" =:
- unlines [ "#+BEGIN_VERSE"
- , " hello darkness"
- , "my old friend"
- , "#+END_VERSE"
- ] =?>
+ T.unlines [ "#+BEGIN_VERSE"
+ , " hello darkness"
+ , "my old friend"
+ , "#+END_VERSE"
+ ] =?>
lineBlock [ "\160\160hello darkness", "my old friend" ]
, "Raw block LaTeX" =:
- unlines [ "#+BEGIN_LaTeX"
- , "The category $\\cat{Set}$ is adhesive."
- , "#+END_LaTeX"
- ] =?>
+ T.unlines [ "#+BEGIN_LaTeX"
+ , "The category $\\cat{Set}$ is adhesive."
+ , "#+END_LaTeX"
+ ] =?>
rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
, "Raw LaTeX line" =:
@@ -1650,24 +1728,24 @@ tests =
rawBlock "html" "<aside>not important</aside>"
, "Export block HTML" =:
- unlines [ "#+BEGIN_export html"
- , "<samp>Hello, World!</samp>"
- , "#+END_export"
- ] =?>
+ T.unlines [ "#+BEGIN_export html"
+ , "<samp>Hello, World!</samp>"
+ , "#+END_export"
+ ] =?>
rawBlock "html" "<samp>Hello, World!</samp>\n"
, "LaTeX fragment" =:
- unlines [ "\\begin{equation}"
- , "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
- , " C_{\\alpha(i)} & \\text{otherwise}"
- , " \\end{cases}"
- , "\\end{equation}"
- ] =?>
+ T.unlines [ "\\begin{equation}"
+ , "X_i = \\begin{cases}"
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
+ , " C_{\\alpha(i)} & \\text{otherwise}"
+ , " \\end{cases}"
+ , "\\end{equation}"
+ ] =?>
rawBlock "latex"
(unlines [ "\\begin{equation}"
, "X_i = \\begin{cases}"
- , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" ++
+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
" \\alpha(i)\\\\"
, " C_{\\alpha(i)} & \\text{otherwise}"
, " \\end{cases}"
@@ -1675,13 +1753,13 @@ tests =
])
, "Code block with caption" =:
- unlines [ "#+CAPTION: Functor laws in Haskell"
- , "#+NAME: functor-laws"
- , "#+BEGIN_SRC haskell"
- , "fmap id = id"
- , "fmap (p . q) = (fmap p) . (fmap q)"
- , "#+END_SRC"
- ] =?>
+ T.unlines [ "#+CAPTION: Functor laws in Haskell"
+ , "#+NAME: functor-laws"
+ , "#+BEGIN_SRC haskell"
+ , "fmap id = id"
+ , "fmap (p . q) = (fmap p) . (fmap q)"
+ , "#+END_SRC"
+ ] =?>
divWith
nullAttr
(mappend
@@ -1693,28 +1771,28 @@ tests =
])))
, "Convert blank lines in blocks to single newlines" =:
- unlines [ "#+begin_html"
- , ""
- , "<span>boring</span>"
- , ""
- , "#+end_html"
- ] =?>
+ T.unlines [ "#+begin_html"
+ , ""
+ , "<span>boring</span>"
+ , ""
+ , "#+end_html"
+ ] =?>
rawBlock "html" "\n<span>boring</span>\n\n"
, "Accept `ATTR_HTML` attributes for generic block" =:
- unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
- , "#+BEGIN_TEST"
- , "nonsense"
- , "#+END_TEST"
- ] =?>
+ T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
+ , "#+BEGIN_TEST"
+ , "nonsense"
+ , "#+END_TEST"
+ ] =?>
let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
in divWith attr (para "nonsense")
, "Non-letter chars in source block parameters" =:
- unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
- , "code body"
- , "#+END_SRC"
- ] =?>
+ T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
+ , "code body"
+ , "#+END_SRC"
+ ] =?>
let params = [ ("data-org-language", "C")
, ("tangle", "xxxx.c")
, ("city", "Zürich")
diff --git a/test/Tests/Readers/RST.hs b/test/Tests/Readers/RST.hs
index 7f67ee742..cbca1564f 100644
--- a/test/Tests/Readers/RST.hs
+++ b/test/Tests/Readers/RST.hs
@@ -2,25 +2,27 @@
{-# LANGUAGE ScopedTypeVariables #-}
module Tests.Readers.RST (tests) where
+import Data.Text (Text)
+import qualified Data.Text as T
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
-rst :: String -> Pandoc
+rst :: Text -> Pandoc
rst = purely $ readRST def{ readerStandalone = True }
infix 4 =:
(=:) :: ToString c
- => String -> (String, c) -> TestTree
+ => String -> (Text, c) -> TestTree
(=:) = test rst
tests :: [TestTree]
tests = [ "line block with blank line" =:
"| a\n|\n| b" =?> lineBlock [ "a", mempty, "\160b" ]
, testGroup "field list"
- [ "general" =: unlines
+ [ "general" =: T.unlines
[ "para"
, ""
, ":Hostname: media08"
@@ -44,7 +46,7 @@ tests = [ "line block with blank line" =:
, (text "Parameter i", [para "integer"])
, (str "Final", [para "item\non two lines"])
])
- , "metadata" =: unlines
+ , "metadata" =: T.unlines
[ "====="
, "Title"
, "====="
@@ -58,7 +60,7 @@ tests = [ "line block with blank line" =:
$ setMeta "title" ("Title" :: Inlines)
$ setMeta "subtitle" ("Subtitle" :: Inlines)
$ doc mempty )
- , "with inline markup" =: unlines
+ , "with inline markup" =: T.unlines
[ ":*Date*: today"
, ""
, ".."
@@ -80,7 +82,7 @@ tests = [ "line block with blank line" =:
])
]
, "URLs with following punctuation" =:
- ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" ++
+ ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" <>
"http://foo.bar/baz_(bam) (http://foo.bar)") =?>
para (link "http://google.com" "" "http://google.com" <> ", " <>
link "http://yahoo.com" "" "http://yahoo.com" <> "; " <>
@@ -89,10 +91,10 @@ tests = [ "line block with blank line" =:
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_\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")
- , "Code directive with class and number-lines" =: unlines
+ , "Code directive with class and number-lines" =: T.unlines
[ ".. code::python"
, " :number-lines: 34"
, " :class: class1 class2 class3"
@@ -107,7 +109,7 @@ tests = [ "line block with blank line" =:
)
"def func(x):\n return y"
)
- , "Code directive with number-lines, no line specified" =: unlines
+ , "Code directive with number-lines, no line specified" =: T.unlines
[ ".. code::python"
, " :number-lines: "
, ""
@@ -122,7 +124,7 @@ tests = [ "line block with blank line" =:
"def func(x):\n return y"
)
, testGroup "literal / line / code blocks"
- [ "indented literal block" =: unlines
+ [ "indented literal block" =: T.unlines
[ "::"
, ""
, " block quotes"
@@ -163,7 +165,7 @@ tests = [ "line block with blank line" =:
, "unknown role" =: ":unknown:`text`" =?> para (str "text")
]
, testGroup "footnotes"
- [ "remove space before note" =: unlines
+ [ "remove space before note" =: T.unlines
[ "foo [1]_"
, ""
, ".. [1]"
diff --git a/test/Tests/Readers/Txt2Tags.hs b/test/Tests/Readers/Txt2Tags.hs
index f6fa4f989..580815279 100644
--- a/test/Tests/Readers/Txt2Tags.hs
+++ b/test/Tests/Readers/Txt2Tags.hs
@@ -2,6 +2,8 @@
module Tests.Readers.Txt2Tags (tests) where
import Data.List (intersperse)
+import Data.Text (Text)
+import qualified Data.Text as T
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -9,7 +11,7 @@ import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
import Text.Pandoc.Class
-t2t :: String -> Pandoc
+t2t :: Text -> Pandoc
-- t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def
t2t = purely $ \s -> do
putCommonState
@@ -20,7 +22,7 @@ t2t = purely $ \s -> do
infix 4 =:
(=:) :: ToString c
- => String -> (String, c) -> TestTree
+ => String -> (Text, c) -> TestTree
(=:) = test t2t
spcSep :: [Inlines] -> Inlines
@@ -154,7 +156,7 @@ tests =
"== header ==[lab/el]" =?>
para (text "== header ==[lab/el]")
, "Headers not preceded by a blank line" =:
- unlines [ "++ eat dinner ++"
+ T.unlines [ "++ eat dinner ++"
, "Spaghetti and meatballs tonight."
, "== walk dog =="
] =?>
@@ -168,16 +170,16 @@ tests =
para "=five"
, "Paragraph containing asterisk at beginning of line" =:
- unlines [ "lucky"
+ T.unlines [ "lucky"
, "*star"
] =?>
para ("lucky" <> softbreak <> "*star")
, "Horizontal Rule" =:
- unlines [ "before"
- , replicate 20 '-'
- , replicate 20 '='
- , replicate 20 '_'
+ T.unlines [ "before"
+ , T.replicate 20 "-"
+ , T.replicate 20 "="
+ , T.replicate 20 "_"
, "after"
] =?>
mconcat [ para "before"
@@ -188,7 +190,7 @@ tests =
]
, "Comment Block" =:
- unlines [ "%%%"
+ T.unlines [ "%%%"
, "stuff"
, "bla"
, "%%%"] =?>
@@ -199,14 +201,14 @@ tests =
, testGroup "Lists" $
[ "Simple Bullet Lists" =:
- ("- Item1\n" ++
+ ("- Item1\n" <>
"- Item2\n") =?>
bulletList [ plain "Item1"
, plain "Item2"
]
, "Indented Bullet Lists" =:
- (" - Item1\n" ++
+ (" - Item1\n" <>
" - Item2\n") =?>
bulletList [ plain "Item1"
, plain "Item2"
@@ -215,13 +217,13 @@ tests =
, "Nested Bullet Lists" =:
- ("- Discovery\n" ++
- " + One More Time\n" ++
- " + Harder, Better, Faster, Stronger\n" ++
- "- Homework\n" ++
- " + Around the World\n"++
- "- Human After All\n" ++
- " + Technologic\n" ++
+ ("- Discovery\n" <>
+ " + One More Time\n" <>
+ " + Harder, Better, Faster, Stronger\n" <>
+ "- Homework\n" <>
+ " + Around the World\n"<>
+ "- Human After All\n" <>
+ " + Technologic\n" <>
" + Robot Rock\n") =?>
bulletList [ mconcat
[ plain "Discovery"
@@ -250,7 +252,7 @@ tests =
]
, "Simple Ordered List" =:
- ("+ Item1\n" ++
+ ("+ Item1\n" <>
"+ Item2\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ plain "Item1"
@@ -260,7 +262,7 @@ tests =
, "Indented Ordered List" =:
- (" + Item1\n" ++
+ (" + Item1\n" <>
" + Item2\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ plain "Item1"
@@ -269,11 +271,11 @@ tests =
in orderedListWith listStyle listStructure
, "Nested Ordered Lists" =:
- ("+ One\n" ++
- " + One-One\n" ++
- " + One-Two\n" ++
- "+ Two\n" ++
- " + Two-One\n"++
+ ("+ One\n" <>
+ " + One-One\n" <>
+ " + One-Two\n" <>
+ "+ Two\n" <>
+ " + Two-One\n"<>
" + Two-Two\n") =?>
let listStyle = (1, DefaultStyle, DefaultDelim)
listStructure = [ mconcat
@@ -292,19 +294,19 @@ tests =
in orderedListWith listStyle listStructure
, "Ordered List in Bullet List" =:
- ("- Emacs\n" ++
+ ("- Emacs\n" <>
" + Org\n") =?>
bulletList [ (plain "Emacs") <>
(orderedList [ plain "Org"])
]
, "Bullet List in Ordered List" =:
- ("+ GNU\n" ++
+ ("+ GNU\n" <>
" - Freedom\n") =?>
orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
, "Definition List" =:
- unlines [ ": PLL"
+ T.unlines [ ": PLL"
, " phase-locked loop"
, ": TTL"
, " transistor-transistor logic"
@@ -318,7 +320,7 @@ tests =
, "Loose bullet list" =:
- unlines [ "- apple"
+ T.unlines [ "- apple"
, ""
, "- orange"
, ""
@@ -340,7 +342,7 @@ tests =
simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
, "Multi line table" =:
- unlines [ "| One |"
+ T.unlines [ "| One |"
, "| Two |"
, "| Three |"
] =?>
@@ -355,7 +357,7 @@ tests =
simpleTable' 1 mempty [[mempty]]
, "Glider Table" =:
- unlines [ "| 1 | 0 | 0 |"
+ T.unlines [ "| 1 | 0 | 0 |"
, "| 0 | 1 | 1 |"
, "| 1 | 1 | 0 |"
] =?>
@@ -367,7 +369,7 @@ tests =
, "Table with Header" =:
- unlines [ "|| Species | Status |"
+ T.unlines [ "|| Species | Status |"
, "| cervisiae | domesticated |"
, "| paradoxus | wild |"
] =?>
@@ -377,7 +379,7 @@ tests =
]
, "Table alignment determined by spacing" =:
- unlines [ "| Numbers | Text | More |"
+ T.unlines [ "| Numbers | Text | More |"
, "| 1 | One | foo |"
, "| 2 | Two | bar |"
] =?>
@@ -394,7 +396,7 @@ tests =
, "Table with differing row lengths" =:
- unlines [ "|| Numbers | Text "
+ T.unlines [ "|| Numbers | Text "
, "| 1 | One | foo |"
, "| 2 "
] =?>
@@ -408,23 +410,23 @@ tests =
, testGroup "Blocks and fragments"
[ "Source block" =:
- unlines [ "```"
+ T.unlines [ "```"
, "main = putStrLn greeting"
, " where greeting = \"moin\""
, "```" ] =?>
- let code' = "main = putStrLn greeting\n" ++
+ let code' = "main = putStrLn greeting\n" <>
" where greeting = \"moin\"\n"
in codeBlock code'
, "tagged block" =:
- unlines [ "'''"
+ T.unlines [ "'''"
, "<aside>HTML5 is pretty nice.</aside>"
, "'''"
] =?>
rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
, "Quote block" =:
- unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!"
+ T.unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!"
] =?>
blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
, "eine", "Mauer", "zu", "errichten!"
diff --git a/test/Tests/Writers/AsciiDoc.hs b/test/Tests/Writers/AsciiDoc.hs
index 02ecb08f4..6b97c0761 100644
--- a/test/Tests/Writers/AsciiDoc.hs
+++ b/test/Tests/Writers/AsciiDoc.hs
@@ -1,5 +1,6 @@
module Tests.Writers.AsciiDoc (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -7,7 +8,7 @@ import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
asciidoc :: (ToPandoc a) => a -> String
-asciidoc = purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc
+asciidoc = unpack . purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc
tests :: [TestTree]
tests = [ testGroup "emphasis"
diff --git a/test/Tests/Writers/ConTeXt.hs b/test/Tests/Writers/ConTeXt.hs
index a5185e19f..783b601a9 100644
--- a/test/Tests/Writers/ConTeXt.hs
+++ b/test/Tests/Writers/ConTeXt.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.ConTeXt (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Test.Tasty.QuickCheck
import Tests.Helpers
@@ -9,10 +10,10 @@ import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
context :: (ToPandoc a) => a -> String
-context = purely (writeConTeXt def) . toPandoc
+context = unpack . purely (writeConTeXt def) . toPandoc
context' :: (ToPandoc a) => a -> String
-context' = purely (writeConTeXt def{ writerWrapText = WrapNone }) . toPandoc
+context' = unpack . purely (writeConTeXt def{ writerWrapText = WrapNone }) . toPandoc
{-
"my test" =: X =?> Y
diff --git a/test/Tests/Writers/Docbook.hs b/test/Tests/Writers/Docbook.hs
index d7da51aed..90ae073fa 100644
--- a/test/Tests/Writers/Docbook.hs
+++ b/test/Tests/Writers/Docbook.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.Docbook (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -11,7 +12,7 @@ docbook :: (ToPandoc a) => a -> String
docbook = docbookWithOpts def{ writerWrapText = WrapNone }
docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
-docbookWithOpts opts = purely (writeDocbook4 opts) . toPandoc
+docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc
{-
"my test" =: X =?> Y
diff --git a/test/Tests/Writers/Docx.hs b/test/Tests/Writers/Docx.hs
index 2d7179199..215952893 100644
--- a/test/Tests/Writers/Docx.hs
+++ b/test/Tests/Writers/Docx.hs
@@ -10,6 +10,8 @@ import Text.Pandoc.Readers.Docx
import Text.Pandoc.Readers.Native
import Text.Pandoc.Writers.Docx
import System.IO.Unsafe (unsafePerformIO) -- TODO temporary
+import qualified Data.ByteString as BS
+import qualified Text.Pandoc.UTF8 as UTF8
type Options = (WriterOptions, ReaderOptions)
@@ -18,8 +20,8 @@ compareOutput :: Options
-> FilePath
-> IO (Pandoc, Pandoc)
compareOutput opts nativeFileIn nativeFileOut = do
- nf <- Prelude.readFile nativeFileIn
- nf' <- Prelude.readFile nativeFileOut
+ nf <- UTF8.toText <$> BS.readFile nativeFileIn
+ nf' <- UTF8.toText <$> BS.readFile nativeFileOut
let wopts = fst opts
df <- runIOorExplode $ do
d <- readNative def nf
diff --git a/test/Tests/Writers/HTML.hs b/test/Tests/Writers/HTML.hs
index 4246b033d..23ff718d3 100644
--- a/test/Tests/Writers/HTML.hs
+++ b/test/Tests/Writers/HTML.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.HTML (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -8,7 +9,7 @@ import Text.Pandoc.Arbitrary ()
import Text.Pandoc.Builder
html :: (ToPandoc a) => a -> String
-html = purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc
+html = unpack . purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc
{-
"my test" =: X =?> Y
diff --git a/test/Tests/Writers/LaTeX.hs b/test/Tests/Writers/LaTeX.hs
index 5f8aea3e0..471d9d9e7 100644
--- a/test/Tests/Writers/LaTeX.hs
+++ b/test/Tests/Writers/LaTeX.hs
@@ -1,6 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
module Tests.Writers.LaTeX (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -14,10 +15,10 @@ latexListing :: (ToPandoc a) => a -> String
latexListing = latexWithOpts def{ writerListings = True }
latexWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-latexWithOpts opts = purely (writeLaTeX opts) . toPandoc
+latexWithOpts opts = unpack . purely (writeLaTeX opts) . toPandoc
beamerWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-beamerWithOpts opts = purely (writeBeamer opts) . toPandoc
+beamerWithOpts opts = unpack . purely (writeBeamer opts) . toPandoc
{-
"my test" =: X =?> Y
diff --git a/test/Tests/Writers/Markdown.hs b/test/Tests/Writers/Markdown.hs
index 5b1e76a29..012e0888c 100644
--- a/test/Tests/Writers/Markdown.hs
+++ b/test/Tests/Writers/Markdown.hs
@@ -2,6 +2,7 @@
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Tests.Writers.Markdown (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -12,10 +13,10 @@ defopts :: WriterOptions
defopts = def{ writerExtensions = pandocExtensions }
markdown :: (ToPandoc a) => a -> String
-markdown = purely (writeMarkdown defopts) . toPandoc
+markdown = unpack . purely (writeMarkdown defopts) . toPandoc
markdownWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-markdownWithOpts opts x = purely (writeMarkdown opts) $ toPandoc x
+markdownWithOpts opts x = unpack . purely (writeMarkdown opts) $ toPandoc x
{-
"my test" =: X =?> Y
diff --git a/test/Tests/Writers/Muse.hs b/test/Tests/Writers/Muse.hs
index 9a7dec580..63fdd293c 100644
--- a/test/Tests/Writers/Muse.hs
+++ b/test/Tests/Writers/Muse.hs
@@ -1,5 +1,6 @@
module Tests.Writers.Muse (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Tests.Helpers
import Text.Pandoc
@@ -10,7 +11,7 @@ muse :: (ToPandoc a) => a -> String
muse = museWithOpts def{ writerWrapText = WrapNone }
museWithOpts :: (ToPandoc a) => WriterOptions -> a -> String
-museWithOpts opts = purely (writeMuse opts) . toPandoc
+museWithOpts opts = unpack . purely (writeMuse opts) . toPandoc
infix 4 =:
(=:) :: (ToString a, ToPandoc a)
@@ -155,8 +156,8 @@ tests = [ testGroup "block elements"
,[para $ text "Para 2.1", para $ text "Para 2.2"]]
in simpleTable [] rows
=?>
- unlines [ "Para 1.1 | Para 1.2"
- , "Para 2.1 | Para 2.2"
+ unlines [ " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
]
, "table with header" =:
let headers = [plain $ text "header 1", plain $ text "header 2"]
@@ -164,9 +165,9 @@ tests = [ testGroup "block elements"
,[para $ text "Para 2.1", para $ text "Para 2.2"]]
in simpleTable headers rows
=?>
- unlines [ "header 1 || header 2"
- , "Para 1.1 | Para 1.2"
- , "Para 2.1 | Para 2.2"
+ unlines [ " header 1 || header 2"
+ , " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
]
, "table with header and caption" =:
let caption = text "Table 1"
@@ -174,10 +175,10 @@ tests = [ testGroup "block elements"
rows = [[para $ text "Para 1.1", para $ text "Para 1.2"]
,[para $ text "Para 2.1", para $ text "Para 2.2"]]
in table caption mempty headers rows
- =?> unlines [ "header 1 || header 2"
- , "Para 1.1 | Para 1.2"
- , "Para 2.1 | Para 2.2"
- , "|+ Table 1 +|"
+ =?> unlines [ " header 1 || header 2"
+ , " Para 1.1 | Para 1.2"
+ , " Para 2.1 | Para 2.2"
+ , " |+ Table 1 +|"
]
]
-- Div is trivial
diff --git a/test/Tests/Writers/Native.hs b/test/Tests/Writers/Native.hs
index c92cb905c..c22185968 100644
--- a/test/Tests/Writers/Native.hs
+++ b/test/Tests/Writers/Native.hs
@@ -1,5 +1,6 @@
module Tests.Writers.Native (tests) where
+import Data.Text (unpack)
import Test.Tasty
import Test.Tasty.QuickCheck
import Tests.Helpers
@@ -8,12 +9,11 @@ import Text.Pandoc.Arbitrary ()
p_write_rt :: Pandoc -> Bool
p_write_rt d =
- read (purely (writeNative def{ writerTemplate = Just "" }) d) == d
+ read (unpack $ purely (writeNative def{ writerTemplate = Just "" }) d) == d
p_write_blocks_rt :: [Block] -> Bool
p_write_blocks_rt bs =
- read (purely (writeNative def) (Pandoc nullMeta bs)) ==
- bs
+ read (unpack $ purely (writeNative def) (Pandoc nullMeta bs)) == bs
tests :: [TestTree]
tests = [ testProperty "p_write_rt" p_write_rt
diff --git a/test/command/1718.md b/test/command/1718.md
new file mode 100644
index 000000000..401610a7a
--- /dev/null
+++ b/test/command/1718.md
@@ -0,0 +1,11 @@
+```
+% pandoc -t native
+Note[^1].
+
+[^1]: the first note.
+
+[^2]: the second, unused, note.
+^D
+[warning] Note with key '2' defined at line 5 column 1 but not used.
+[Para [Str "Note",Note [Para [Str "the",Space,Str "first",Space,Str "note."]],Str "."]]
+```
diff --git a/test/command/1841.md b/test/command/1841.md
new file mode 100644
index 000000000..408f224bd
--- /dev/null
+++ b/test/command/1841.md
@@ -0,0 +1,42 @@
+```
+% pandoc
+<table>
+<tr>
+<td> *one*</td>
+<td> [a link](http://google.com)</td>
+</tr>
+</table>
+^D
+<table>
+<tr>
+<td>
+<em>one</em>
+</td>
+<td>
+<a href="http://google.com">a link</a>
+</td>
+</tr>
+</table>
+```
+
+```
+% pandoc
+<table>
+ <tr>
+ <td>*one*</td>
+ <td>[a link](http://google.com)</td>
+ </tr>
+</table>
+^D
+<table>
+<tr>
+<td>
+<em>one</em>
+</td>
+<td>
+<a href="http://google.com">a link</a>
+</td>
+</tr>
+</table>
+```
+
diff --git a/test/command/2228.md b/test/command/2228.md
new file mode 100644
index 000000000..589a2350e
--- /dev/null
+++ b/test/command/2228.md
@@ -0,0 +1,6 @@
+```
+% pandoc -f markdown+smart -t latex+smart
+*foo*'s 'foo'
+^D
+\emph{foo}'s `foo'
+```
diff --git a/test/command/2602.md b/test/command/2602.md
new file mode 100644
index 000000000..5ed4b581c
--- /dev/null
+++ b/test/command/2602.md
@@ -0,0 +1,18 @@
+```
+% pandoc
+[a] [b]
+
+[b]: url
+^D
+<p>[a] <a href="url">b</a></p>
+```
+
+```
+% pandoc -f markdown+spaced_reference_links
+[a] [b]
+
+[b]: url
+^D
+<p><a href="url">a</a></p>
+```
+
diff --git a/test/command/3113.md b/test/command/3113.md
new file mode 100644
index 000000000..f44e25709
--- /dev/null
+++ b/test/command/3113.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f latex -t native
+\begin{eqnarray}
+A&=&B,\\
+C&=&D,\\
+%\end{eqnarray}
+%\begin{eqnarray}
+E&=&F
+\end{eqnarray}
+^D
+[Para [Math DisplayMath "\\begin{aligned}\nA&=&B,\\\\\nC&=&D,\\\\\nE&=&F\\end{aligned}"]]
+```
+
diff --git a/test/command/3314.md b/test/command/3314.md
new file mode 100644
index 000000000..064b04cbd
--- /dev/null
+++ b/test/command/3314.md
@@ -0,0 +1,34 @@
+See #3315 and <http://docutils.sourceforge.net/docs/ref/rst/restructuredtext.html#simple-tables>.
+
+```
+% pandoc -f org -t html5
++-----------+-------+----------+
+| First | 12.0 | Example |
+| | | row |
+| | | spanning |
+| | | lines |
++-----------+-------+----------+
+| Second | 5.0 | Another |
++-----------+-------+----------+
+^D
+<table style="width:43%;">
+<colgroup>
+<col style="width: 16%" />
+<col style="width: 11%" />
+<col style="width: 15%" />
+</colgroup>
+<tbody>
+<tr class="odd">
+<td>First</td>
+<td>12.0</td>
+<td>Example row spanning lines</td>
+</tr>
+<tr class="even">
+<td>Second</td>
+<td>5.0</td>
+<td>Another</td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/3401.md b/test/command/3401.md
new file mode 100644
index 000000000..99528553a
--- /dev/null
+++ b/test/command/3401.md
@@ -0,0 +1,19 @@
+See #3401 and <http://orgmode.org/manual/Macro-replacement.html>
+
+```
+% pandoc -f org -t native
+#+MACRO: HELLO /Hello, $1/
+{{{HELLO(World)}}}
+^D
+[Para [Emph [Str "Hello,",Space,Str "World"]]]
+```
+
+Inverted argument order
+
+```
+% pandoc -f org -t native
+#+MACRO: A $2,$1
+{{{A(1,2)}}}
+^D
+[Para [Str "2,1"]]
+```
diff --git a/test/command/3432.md b/test/command/3432.md
new file mode 100644
index 000000000..7264d22c3
--- /dev/null
+++ b/test/command/3432.md
@@ -0,0 +1,289 @@
+List-table with header-rows and widths options.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :widths: 15 10 30
+ :header-rows: 1
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<colgroup>
+<col style="width: 27%" />
+<col style="width: 18%" />
+<col style="width: 54%" />
+</colgroup>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table whose widths is "auto".
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 1
+ :widths: auto
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+
+List-table with header-rows which is bigger than 1. Only the first row is treated as a header.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 2
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table without header-rows.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+
+ * - Albatross
+ - 2.99
+ - On a stick!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td>On a stick!</td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table with empty cells. You need a space after '-', otherwise the row will disapear. Parser for Bulletlists causes this ristriction.
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+ :header-rows: 2
+
+ * - Treat
+ - Quantity
+ - Description
+ * - Albatross
+ - 2.99
+ -
+ * - Crunchy Frog
+ -
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<thead>
+<tr class="header">
+<th>Treat</th>
+<th>Quantity</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td></td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td></td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
+
+List-table with a cell having a bulletlist
+
+```
+% pandoc -f rst
+.. list-table:: Frozen Delights!
+
+ * - Albatross
+ - 2.99
+ - + On a stick!
+ + In a cup!
+ * - Crunchy Frog
+ - 1.49
+ - If we took the bones out, it wouldn't be
+ crunchy, now would it?
+ * - Gannet Ripple
+ - 1.99
+ - On a stick!
+^D
+<table>
+<caption>Frozen Delights!</caption>
+<tbody>
+<tr class="odd">
+<td>Albatross</td>
+<td>2.99</td>
+<td><ul>
+<li>On a stick!</li>
+<li>In a cup!</li>
+</ul></td>
+</tr>
+<tr class="even">
+<td>Crunchy Frog</td>
+<td>1.49</td>
+<td>If we took the bones out, it wouldn't be crunchy, now would it?</td>
+</tr>
+<tr class="odd">
+<td>Gannet Ripple</td>
+<td>1.99</td>
+<td>On a stick!</td>
+</tr>
+</tbody>
+</table>
+```
diff --git a/test/command/3450.md b/test/command/3450.md
new file mode 100644
index 000000000..8759aa0c1
--- /dev/null
+++ b/test/command/3450.md
@@ -0,0 +1,12 @@
+```
+% pandoc -fmarkdown-implicit_figures
+![image](lalune.jpg){height=2em}
+^D
+<p><img src="lalune.jpg" alt="image" style="height:2em" /></p>
+```
+```
+% pandoc -fmarkdown-implicit_figures -t latex
+![image](lalune.jpg){height=2em}
+^D
+\includegraphics[height=2em]{lalune.jpg}
+```
diff --git a/test/command/3494.md b/test/command/3494.md
index faa58c321..7c480fde6 100644
--- a/test/command/3494.md
+++ b/test/command/3494.md
@@ -1,5 +1,5 @@
```
-% pandoc -f latex
+% pandoc -f latex --quiet
\begin{table}[h!]
\begin{tabular}{r|l|l}
diff --git a/test/command/3510-export.latex b/test/command/3510-export.latex
new file mode 100644
index 000000000..6d8636322
--- /dev/null
+++ b/test/command/3510-export.latex
@@ -0,0 +1 @@
+\emph{Hello} \ No newline at end of file
diff --git a/test/command/3510-src.hs b/test/command/3510-src.hs
new file mode 100644
index 000000000..ad5744b80
--- /dev/null
+++ b/test/command/3510-src.hs
@@ -0,0 +1 @@
+putStrLn outString
diff --git a/test/command/3510-subdoc.org b/test/command/3510-subdoc.org
new file mode 100644
index 000000000..5bcc6678a
--- /dev/null
+++ b/test/command/3510-subdoc.org
@@ -0,0 +1,5 @@
+* Subsection
+
+Included text
+
+Lorem ipsum.
diff --git a/test/command/3510.md b/test/command/3510.md
new file mode 100644
index 000000000..7993db848
--- /dev/null
+++ b/test/command/3510.md
@@ -0,0 +1,20 @@
+See <http://orgmode.org/manual/Include-files.html>
+```
+% pandoc -f org -t native
+Text
+
+#+include: "command/3510-subdoc.org"
+
+#+INCLUDE: "command/3510-src.hs" src haskell
+#+INCLUDE: "command/3510-export.latex" export latex
+
+More text
+^D
+[Para [Str "Text"]
+,Header 1 ("subsection",[],[]) [Str "Subsection"]
+,Para [Str "Included",Space,Str "text"]
+,Plain [Str "Lorem",Space,Str "ipsum."]
+,CodeBlock ("",["haskell"],[]) "putStrLn outString\n"
+,RawBlock (Format "latex") "\\emph{Hello}"
+,Para [Str "More",Space,Str "text"]]
+```
diff --git a/test/command/3516.md b/test/command/3516.md
index 982043874..8c7e478d3 100644
--- a/test/command/3516.md
+++ b/test/command/3516.md
@@ -27,8 +27,8 @@ on Windows builds.
[Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
[[]
,[]]
- [[[Para [Str "1"]]
- ,[Para [Str "2"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "2"]]]
,[[]
,[]]]]
```
diff --git a/test/command/3577.md b/test/command/3577.md
index bfeb86eaa..dc88937e9 100644
--- a/test/command/3577.md
+++ b/test/command/3577.md
@@ -1,5 +1,5 @@
```
-% pandoc -f latex -t html5
+% pandoc -f latex -t html5 --quiet
\begin{figure}[ht]
\begin{subfigure}{0.45\textwidth}
\centering
diff --git a/test/command/3585.md b/test/command/3585.md
new file mode 100644
index 000000000..739ddeea4
--- /dev/null
+++ b/test/command/3585.md
@@ -0,0 +1,16 @@
+```
+% pandoc -f mediawiki+smart -t native
+"Hello"
+
+Same but bzip2 it and nice it <tt>zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org "> /storage/c-3po/tank-storage-data-svn.dmp.bz2"</tt>
+^D
+[Para [Quoted DoubleQuote [Str "Hello"]]
+,Para [Str "Same",Space,Str "but",Space,Str "bzip2",Space,Str "it",Space,Str "and",Space,Str "nice",Space,Str "it",Space,Code ("",[],[]) "zfs send tank/storage/data/svn@daily-2014-03-20_00.00.00--2w | nice -15 bzip2 | ssh user@hyper.somewhere.org \"> /storage/c-3po/tank-storage-data-svn.dmp.bz2\""]]
+```
+
+```
+% pandoc -f mediawiki -t native
+"Hello"
+^D
+[Para [Str "\"Hello\""]]
+```
diff --git a/test/command/3619.md b/test/command/3619.md
new file mode 100644
index 000000000..62962c43b
--- /dev/null
+++ b/test/command/3619.md
@@ -0,0 +1,28 @@
+```
+% pandoc -f html -t markdown --reference-links
+<a href="foo">bar</a>: baz
+^D
+[bar][]: baz
+
+ [bar]: foo
+```
+
+```
+% pandoc -f html -t markdown --reference-links
+<a href="foo">bar</a>(baz)
+^D
+[bar][](baz)
+
+ [bar]: foo
+```
+
+```
+% pandoc -f html -t markdown_strict --reference-links
+<a href="a">foo</a><br/><a href="b">bar</a>
+^D
+[foo][]
+[bar]
+
+ [foo]: a
+ [bar]: b
+```
diff --git a/test/command/3630.md b/test/command/3630.md
new file mode 100644
index 000000000..db3a17dda
--- /dev/null
+++ b/test/command/3630.md
@@ -0,0 +1,8 @@
+```
+% pandoc -f markdown -t markdown --reference-links
+![foo](bar.png){#myId}
+^D
+![foo]
+
+ [foo]: bar.png {#myId}
+```
diff --git a/test/command/3667.md b/test/command/3667.md
new file mode 100644
index 000000000..97de8f598
--- /dev/null
+++ b/test/command/3667.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f textile
+| "link text":http://example.com/ |
+^D
+<table>
+<tbody>
+<tr class="odd">
+<td><a href="http://example.com/">link text</a></td>
+</tr>
+</tbody>
+</table>
+```
+
diff --git a/test/command/3674.md b/test/command/3674.md
new file mode 100644
index 000000000..92ed4bed7
--- /dev/null
+++ b/test/command/3674.md
@@ -0,0 +1,39 @@
+Make sure we don't get duplicate reference links, even with
+`--reference-location=section`.
+
+```
+% pandoc --reference-links -t markdown --reference-location=section --atx-headers
+# a
+
+![](a)
+
+# b
+
+![](b)
+
+^D
+# a
+
+![][1]
+
+ [1]: a
+
+# b
+
+![][2]
+
+ [2]: b
+```
+
+Subsidiary issue: allow line break between reference link
+url/title and attributes:
+
+```
+% pandoc
+[a]
+
+[a]: url
+{.class}
+^D
+<p><a href="url" class="class">a</a></p>
+```
diff --git a/test/command/3675.md b/test/command/3675.md
new file mode 100644
index 000000000..b129c7a63
--- /dev/null
+++ b/test/command/3675.md
@@ -0,0 +1,15 @@
+````
+% pandoc -t rst
+```python
+print("hello")
+```
+> block quote
+^D
+.. code:: python
+
+ print("hello")
+
+..
+
+ block quote
+````
diff --git a/test/command/3690.md b/test/command/3690.md
new file mode 100644
index 000000000..213b88138
--- /dev/null
+++ b/test/command/3690.md
@@ -0,0 +1,8 @@
+```
+% pandoc
+- [o] _hi_
+^D
+<ul>
+<li>[o] <em>hi</em></li>
+</ul>
+```
diff --git a/test/command/3701.md b/test/command/3701.md
new file mode 100644
index 000000000..01e438639
--- /dev/null
+++ b/test/command/3701.md
@@ -0,0 +1,60 @@
+```
+% pandoc --reference-location=block -t markdown --reference-links --wrap=preserve
+[a](u)
+
+[a](u)
+
+[a](u2)
+[A](u)
+[a](u){.foo}
+
+[a](u3)
+^D
+[a]
+
+ [a]: u
+
+[a]
+
+ [a]: u
+
+[a][1]
+[A][]
+[a][2]
+
+ [1]: u2
+ [A]: u
+ [2]: u {.foo}
+
+[a][3]
+
+ [3]: u3
+```
+
+```
+% pandoc
+[a]
+
+ [a]: u
+
+[a]
+
+ [a]: u
+
+[a][1]
+[A][]
+[a][2]
+
+ [1]: u2
+ [A]: u
+ [2]: u {.foo}
+
+[a][3]
+
+ [3]: u3
+^D
+<p><a href="u">a</a></p>
+<p><a href="u">a</a></p>
+<p><a href="u2">a</a> <a href="u">A</a> <a href="u" class="foo">a</a></p>
+<p><a href="u3">a</a></p>
+```
diff --git a/test/command/3706.md b/test/command/3706.md
new file mode 100644
index 000000000..00f53279e
--- /dev/null
+++ b/test/command/3706.md
@@ -0,0 +1,44 @@
+Results marker can be hidden in block attributes (#3706)
+
+```
+pandoc -f org -t native
+#+BEGIN_SRC R :exports results :colnames yes
+ data.frame(Id = 1:3, Desc = rep("La",3))
+#+END_SRC
+
+#+CAPTION: Lalelu.
+#+LABEL: tab
+#+RESULTS:
+| Id | Desc |
+|----+------|
+| 1 | La |
+| 2 | La |
+| 3 | La |
+^D
+[Table [Str "Lalelu."] [AlignDefault,AlignDefault] [0.0,0.0]
+ [[Plain [Str "Id"]]
+ ,[Plain [Str "Desc"]]]
+ [[[Plain [Str "1"]]
+ ,[Plain [Str "La"]]]
+ ,[[Plain [Str "2"]]
+ ,[Plain [Str "La"]]]
+ ,[[Plain [Str "3"]]
+ ,[Plain [Str "La"]]]]]
+```
+
+```
+pandoc -f org -t native
+#+BEGIN_SRC R :exports none :colnames yes
+ data.frame(Id = 1:2, Desc = rep("La",2))
+#+END_SRC
+
+#+CAPTION: Lalelu.
+#+LABEL: tab
+#+RESULTS:
+| Id | Desc |
+|----+------|
+| 1 | La |
+| 2 | La |
+^D
+[]
+```
diff --git a/test/command/3708.md b/test/command/3708.md
new file mode 100644
index 000000000..2cbc82c25
--- /dev/null
+++ b/test/command/3708.md
@@ -0,0 +1,15 @@
+```
+% pandoc -f latex -t native
+\begin{tabular}{cc}
+ A & B\&1 \\
+ C & D
+\end{tabular}
+^D
+[Table [] [AlignCenter,AlignCenter] [0.0,0.0]
+ [[]
+ ,[]]
+ [[[Plain [Str "A"]]
+ ,[Plain [Str "B&1"]]]
+ ,[[Plain [Str "C"]]
+ ,[Plain [Str "D"]]]]]
+```
diff --git a/test/command/3715.md b/test/command/3715.md
new file mode 100644
index 000000000..9d74779cb
--- /dev/null
+++ b/test/command/3715.md
@@ -0,0 +1,15 @@
+```
+% pandoc -t markdown -f html --wrap=preserve
+x<em></em>x
+y<strong></strong>y
+z<sup></sup>z
+w<sub></sub>w
+q<s></s>q
+^D
+xx
+yy
+zz
+ww
+qq
+```
+
diff --git a/test/command/3716.md b/test/command/3716.md
new file mode 100644
index 000000000..7e00819da
--- /dev/null
+++ b/test/command/3716.md
@@ -0,0 +1,6 @@
+```
+% pandoc
+<http://example.com>{.foo}
+^D
+<p><a href="http://example.com" class="uri foo">http://example.com</a></p>
+```
diff --git a/test/command/3730.md b/test/command/3730.md
new file mode 100644
index 000000000..fbc06cbce
--- /dev/null
+++ b/test/command/3730.md
@@ -0,0 +1,21 @@
+````
+% pandoc
+nice line\
+```
+code
+```
+^D
+<p>nice line<br />
+</p>
+<pre><code>code</code></pre>
+````
+
+```
+% pandoc
+# hi\
+there
+^D
+<h1 id="hi">hi<br />
+</h1>
+<p>there</p>
+```
diff --git a/test/command/3736.md b/test/command/3736.md
new file mode 100644
index 000000000..b66e0a359
--- /dev/null
+++ b/test/command/3736.md
@@ -0,0 +1,25 @@
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi
+there</h2>
+^D
+hi there
+--------
+```
+
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi <em>there
+again</em></h2>
+^D
+hi *there again*
+----------------
+```
+
+```
+% pandoc --wrap=preserve -f html -t markdown
+<h2>hi<br>there</h2>
+^D
+hi there
+--------
+```
diff --git a/test/command/512.md b/test/command/512.md
index a13c434f6..52e5dbe07 100644
--- a/test/command/512.md
+++ b/test/command/512.md
@@ -36,6 +36,7 @@ Loop detection:
__ link1_
^D
+[warning] Circular reference 'link1' at line 1 column 15
<p><a href="">click here</a></p>
```
diff --git a/test/command/SVG_logo-without-xml-declaration.svg b/test/command/SVG_logo-without-xml-declaration.svg
new file mode 100644
index 000000000..febcab6ca
--- /dev/null
+++ b/test/command/SVG_logo-without-xml-declaration.svg
@@ -0,0 +1,32 @@
+<svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<title>SVG Logo</title>
+<rect id="background" x="-50" y="-50" width="100" height="100" rx="4" fill="#f90"/>
+<rect id="top-left" x="-50" y="-50" width="50" height="50" rx="4" fill="#ffb13b"/>
+<rect id="bottom-right" width="50" height="50" rx="4" fill="#de8500"/>
+<use stroke="#f90" stroke-width="22.6" xlink:href="#a"/>
+<circle r="26"/>
+<use stroke="#000" stroke-width="12" xlink:href="#a"/>
+<g id="a">
+ <g id="b">
+ <g id="c">
+ <circle id="n" cy="-31.6" r="7.1" fill="#fff"/>
+ <path d="m0 31.6v-63.2" stroke="#fff" stroke-width="10"/>
+ <use y="63.2" xlink:href="#n"/>
+ </g>
+ <use transform="rotate(90)" xlink:href="#c"/>
+ </g>
+ <use transform="rotate(45)" xlink:href="#b"/>
+</g>
+<path id="text-backdrop" d="m44.68 0v40c0 3.333-1.667 5-5 5h-79.38c-3.333 0-5-1.667-5-5v-40"/>
+<path id="shine" d="m36 4.21c2.9 0 5.3 2.4 5.3 5.3v18c-27.6-3.4-54.9-8-82-7.7v-10.2c0-2.93 2.4-5.3 5.3-5.3z" fill="#3f3f3f"/>
+<use stroke="#000" stroke-width="7.4" xlink:href="#s"/>
+<g id="svg-text" stroke="#fff" stroke-width="6.4">
+ <g id="s">
+ <path fill="none" d="m-31.74 31.17a8.26 8.26 0 1 0 8.26 -8.26 8.26 8.26 0 1 1 8.26 -8.26M23.23 23h8.288v 8.26a8.26 8.26 0 0 1 -16.52 0v-16.52a8.26 8.26 0 0 1 16.52 0"/>
+ <g stroke-width=".5" stroke="#000">
+ <path d="m4.76 3h6.83l-8.24 39.8h-6.85l-8.26-39.8h6.85l4.84 23.3z" fill="#fff"/>
+ <path d="m23.23 19.55v6.9m4.838-11.71h6.9m-70.16 16.43h6.9m9.62-16.52h6.9" stroke-linecap="square"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/test/command/SVG_logo.svg b/test/command/SVG_logo.svg
new file mode 100644
index 000000000..5333a5ddb
--- /dev/null
+++ b/test/command/SVG_logo.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0"?>
+<svg viewBox="-50 -50 100 100" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+<title>SVG Logo</title>
+<rect id="background" x="-50" y="-50" width="100" height="100" rx="4" fill="#f90"/>
+<rect id="top-left" x="-50" y="-50" width="50" height="50" rx="4" fill="#ffb13b"/>
+<rect id="bottom-right" width="50" height="50" rx="4" fill="#de8500"/>
+<use stroke="#f90" stroke-width="22.6" xlink:href="#a"/>
+<circle r="26"/>
+<use stroke="#000" stroke-width="12" xlink:href="#a"/>
+<g id="a">
+ <g id="b">
+ <g id="c">
+ <circle id="n" cy="-31.6" r="7.1" fill="#fff"/>
+ <path d="m0 31.6v-63.2" stroke="#fff" stroke-width="10"/>
+ <use y="63.2" xlink:href="#n"/>
+ </g>
+ <use transform="rotate(90)" xlink:href="#c"/>
+ </g>
+ <use transform="rotate(45)" xlink:href="#b"/>
+</g>
+<path id="text-backdrop" d="m44.68 0v40c0 3.333-1.667 5-5 5h-79.38c-3.333 0-5-1.667-5-5v-40"/>
+<path id="shine" d="m36 4.21c2.9 0 5.3 2.4 5.3 5.3v18c-27.6-3.4-54.9-8-82-7.7v-10.2c0-2.93 2.4-5.3 5.3-5.3z" fill="#3f3f3f"/>
+<use stroke="#000" stroke-width="7.4" xlink:href="#s"/>
+<g id="svg-text" stroke="#fff" stroke-width="6.4">
+ <g id="s">
+ <path fill="none" d="m-31.74 31.17a8.26 8.26 0 1 0 8.26 -8.26 8.26 8.26 0 1 1 8.26 -8.26M23.23 23h8.288v 8.26a8.26 8.26 0 0 1 -16.52 0v-16.52a8.26 8.26 0 0 1 16.52 0"/>
+ <g stroke-width=".5" stroke="#000">
+ <path d="m4.76 3h6.83l-8.24 39.8h-6.85l-8.26-39.8h6.85l4.84 23.3z" fill="#fff"/>
+ <path d="m23.23 19.55v6.9m4.838-11.71h6.9m-70.16 16.43h6.9m9.62-16.52h6.9" stroke-linecap="square"/>
+ </g>
+ </g>
+</g>
+</svg>
diff --git a/test/command/corrupt.svg b/test/command/corrupt.svg
new file mode 100644
index 000000000..cfaa697f0
--- /dev/null
+++ b/test/command/corrupt.svg
@@ -0,0 +1,5 @@
+Lorem ipsum dolor sit amet etiam. A pede dolor neque pretium luctus pharetra vel rutrum. Orci nonummy ac. At eu est tempor
+proin wisi. Nunc tincidunt proin. Suspendisse lorem commodo. Integer diam diam semper commodo dictum et tellus eu ultrices
+nec erat pulvinar porttitor nulla nulla mauris orci libero eros elementum et possimus voluptate. Velit morbi et. Luctus diam
+in. Lorem tincidunt sem dolor rerum mauris. Dis taciti posuere pellentesque sed rutrum. Lectus donec fusce in dictum pede.
+In etiam congue. Aliquam aliquet elit arcu mauris enim. Risus at enim.
diff --git a/test/command/inkscape-cube.svg b/test/command/inkscape-cube.svg
new file mode 100644
index 000000000..995c3c734
--- /dev/null
+++ b/test/command/inkscape-cube.svg
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="38.772217mm"
+ height="46.163891mm"
+ viewBox="0 0 38.772217 46.163891"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="cube.svg">
+ <defs
+ id="defs2">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="-48.380952 : -45.023815 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="161.61905 : -45.023817 : 1"
+ inkscape:persp3d-origin="56.619048 : -94.523816 : 1"
+ id="perspective4485" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.98994949"
+ inkscape:cx="-63.181251"
+ inkscape:cy="-116.38602"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ fit-margin-top="0"
+ fit-margin-left="0"
+ fit-margin-right="0"
+ fit-margin-bottom="0"
+ inkscape:window-width="1920"
+ inkscape:window-height="1136"
+ inkscape:window-x="1920"
+ inkscape:window-y="30"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Ebene 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(-149.67857,78.746839)">
+ <g
+ sodipodi:type="inkscape:box3d"
+ id="g4487"
+ style="opacity:0.2;fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.53100002;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
+ inkscape:perspectiveID="#perspective4485"
+ inkscape:corner0="1.1045097 : 0.18860662 : 0 : 1"
+ inkscape:corner7="0.52634769 : 0.15538942 : 0.25 : 1">
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4489"
+ style="fill:#353564;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="6"
+ d="m 151.19047,-53.658435 v 15.783818 l 17.00006,5.342459 v -14.107905 z"
+ points="151.19047,-37.874617 168.19053,-32.532158 168.19053,-46.640063 151.19047,-53.658435 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4499"
+ style="fill:#e9e9ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="11"
+ d="m 168.19053,-46.640063 21.77216,-19.229539 v 18.699717 l -21.77216,14.637727 z"
+ points="189.96269,-65.869602 189.96269,-47.169885 168.19053,-32.532158 168.19053,-46.640063 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4491"
+ style="fill:#4d4d9f;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="5"
+ d="m 151.19047,-53.658435 18.89881,-25.037614 19.87341,12.826447 -21.77216,19.229539 z"
+ points="170.08928,-78.696049 189.96269,-65.869602 168.19053,-46.640063 151.19047,-53.658435 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4497"
+ style="fill:#afafde;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="13"
+ d="m 151.19047,-37.874617 18.89881,-19.058894 19.87341,9.763626 -21.77216,14.637727 z"
+ points="170.08928,-56.933511 189.96269,-47.169885 168.19053,-32.532158 151.19047,-37.874617 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4495"
+ style="fill:#d7d7ff;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="14"
+ d="m 170.08928,-78.696049 v 21.762538 l 19.87341,9.763626 v -18.699717 z"
+ points="170.08928,-56.933511 189.96269,-47.169885 189.96269,-65.869602 170.08928,-78.696049 " />
+ <path
+ sodipodi:type="inkscape:box3dside"
+ id="path4493"
+ style="fill:#8686bf;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1"
+ inkscape:box3dsidetype="3"
+ d="m 151.19047,-53.658435 18.89881,-25.037614 v 21.762538 l -18.89881,19.058894 z"
+ points="170.08928,-78.696049 170.08928,-56.933511 151.19047,-37.874617 151.19047,-53.658435 " />
+ </g>
+ </g>
+</svg>
diff --git a/test/command/latex-fontawesome.md b/test/command/latex-fontawesome.md
new file mode 100644
index 000000000..2a7e91185
--- /dev/null
+++ b/test/command/latex-fontawesome.md
@@ -0,0 +1,13 @@
+```
+% pandoc -f latex -t native
+Check: \faCheck
+^D
+[Para [Str "Check:",Space,Str "\10003"]]
+```
+
+```
+% pandoc -f latex -t native
+Close: \faClose
+^D
+[Para [Str "Close:",Space,Str "\10007"]]
+```
diff --git a/test/command/lstlisting.md b/test/command/lstlisting.md
new file mode 100644
index 000000000..d928cc702
--- /dev/null
+++ b/test/command/lstlisting.md
@@ -0,0 +1,25 @@
+```
+% pandoc -f latex -t native
+\begin{lstlisting}[language=Java, caption={Java Example}, label=lst:Hello-World]
+public class World {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
+\end{lstlisting}
+^D
+[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"]
+```
+
+```
+% pandoc -f latex -t native
+\begin{lstlisting}[language=Java, escapechar=|, caption={Java Example}, label=lst:Hello-World]
+public class World {
+ public static void main(String[] args) {
+ System.out.println("Hello World");
+ }
+}
+\end{lstlisting}
+^D
+[CodeBlock ("lst:Hello-World",["java"],[("language","Java"),("escapechar","|"),("caption","Java Example"),("label","lst:Hello-World")]) "public class World {\n public static void main(String[] args) {\n System.out.println(\"Hello World\");\n }\n}"]
+```
diff --git a/test/command/parse-raw.md b/test/command/parse-raw.md
index f4e493c69..6c91c2fa9 100644
--- a/test/command/parse-raw.md
+++ b/test/command/parse-raw.md
@@ -9,6 +9,7 @@
% pandoc -f latex -t markdown
\emph{Hi \foo{there}}
^D
+[warning] Skipped '\foo{there}' at line 1 column 21
*Hi*
```
@@ -23,5 +24,7 @@
% pandoc -f html -t markdown
<em>Hi <blink>there</blink></em>
^D
+[warning] Skipped '<blink>' at input line 1 column 8
+[warning] Skipped '</blink>' at input line 1 column 20
*Hi there*
```
diff --git a/test/command/svg.md b/test/command/svg.md
new file mode 100644
index 000000000..b48745f9a
--- /dev/null
+++ b/test/command/svg.md
@@ -0,0 +1,132 @@
+```
+% pandoc -f latex -t icml
+\includegraphics{command/corrupt.svg}
+^D
+[warning] Could not determine image size for 'command/corrupt.svg': could not determine image type
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/corrupt.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/SVG_logo.svg}
+^D
+[warning] Could not determine image size for 'command/SVG_logo.svg': could not determine SVG size
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/SVG_logo.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/SVG_logo-without-xml-declaration.svg}
+^D
+[warning] Could not determine image size for 'command/SVG_logo-without-xml-declaration.svg': could not determine SVG size
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 150 -100">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-150 -100" LeftDirection="-150 -100" RightDirection="-150 -100" />
+ <PathPointType Anchor="-150 100" LeftDirection="-150 100" RightDirection="-150 100" />
+ <PathPointType Anchor="150 100" LeftDirection="150 100" RightDirection="150 100" />
+ <PathPointType Anchor="150 -100" LeftDirection="150 -100" RightDirection="150 -100" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -150 -100">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/SVG_logo-without-xml-declaration.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
+
+```
+% pandoc -f latex -t icml
+\includegraphics{command/inkscape-cube.svg}
+^D
+<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
+ <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 54.75 -65.25">
+ <Properties>
+ <PathGeometry>
+ <GeometryPathType PathOpen="false">
+ <PathPointArray>
+ <PathPointType Anchor="-54.75 -65.25" LeftDirection="-54.75 -65.25" RightDirection="-54.75 -65.25" />
+ <PathPointType Anchor="-54.75 65.25" LeftDirection="-54.75 65.25" RightDirection="-54.75 65.25" />
+ <PathPointType Anchor="54.75 65.25" LeftDirection="54.75 65.25" RightDirection="54.75 65.25" />
+ <PathPointType Anchor="54.75 -65.25" LeftDirection="54.75 -65.25" RightDirection="54.75 -65.25" />
+ </PathPointArray>
+ </GeometryPathType>
+ </PathGeometry>
+ </Properties>
+ <Image Self="ue6" ItemTransform="1 0 0 1 -54.75 -65.25">
+ <Properties>
+ <Profile type="string">
+ $ID/Embedded
+ </Profile>
+ </Properties>
+ <Link Self="ueb" LinkResourceURI="file:command/inkscape-cube.svg" />
+ </Image>
+ </Rectangle>
+ </CharacterStyleRange>
+</ParagraphStyleRange>
+```
+
diff --git a/test/command/tabularx.md b/test/command/tabularx.md
new file mode 100644
index 000000000..bf7670e9c
--- /dev/null
+++ b/test/command/tabularx.md
@@ -0,0 +1,110 @@
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|c|c|c|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignCenter,AlignCenter,AlignCenter] [0.0,0.0,0.0]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
+
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|X|c|p{0.25\linewidth}|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.0,0.0,0.25]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
+
+```
+% pandoc -f latex -t native --quiet
+\begin{tabularx}{\linewidth}{|b{0.25\linewidth}|c|m{0.25\linewidth}|}
+\hline
+ Column Heading 1
+ & Column Heading 2
+ & Column Heading 3 \\
+\hline
+ Cell 1.1
+ & Cell 1.2
+ & Cell 1.3 \\
+\hline
+ Cell 2.1
+ & Cell 2.2
+ & Cell 2.3 \\
+\hline
+ Cell 3.1
+ & Cell 3.2
+ & Cell 3.3 \\
+\hline
+\end{tabularx}
+^D
+[Table [] [AlignLeft,AlignCenter,AlignLeft] [0.25,0.0,0.25]
+ [[Plain [Str "Column",Space,Str "Heading",Space,Str "1"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "2"]]
+ ,[Plain [Str "Column",Space,Str "Heading",Space,Str "3"]]]
+ [[[Plain [Str "Cell",Space,Str "1.1"]]
+ ,[Plain [Str "Cell",Space,Str "1.2"]]
+ ,[Plain [Str "Cell",Space,Str "1.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "2.1"]]
+ ,[Plain [Str "Cell",Space,Str "2.2"]]
+ ,[Plain [Str "Cell",Space,Str "2.3"]]]
+ ,[[Plain [Str "Cell",Space,Str "3.1"]]
+ ,[Plain [Str "Cell",Space,Str "3.2"]]
+ ,[Plain [Str "Cell",Space,Str "3.3"]]]]]
+```
diff --git a/test/fb2/titles.fb2 b/test/fb2/titles.fb2
index 9e8d47e36..0a3b1404e 100644
--- a/test/fb2/titles.fb2
+++ b/test/fb2/titles.fb2
@@ -1,3 +1,3 @@
<?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 /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><title><p>Simple title</p></title><p>This example tests if Pandoc doesn’t insert forbidden elements in FictionBook titles.</p></section><section><title><p>Emphasized Strong Title</p></title></section><section><title><p>Title with</p><empty-line /><p>line break</p></title></section></body></FictionBook>
+<FictionBook xmlns="http://www.gribuser.ru/xml/fictionbook/2.0" xmlns:l="http://www.w3.org/1999/xlink"><description><title-info /><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><annotation><p></p></annotation><section><title><p>Simple title</p></title><p>This example tests if Pandoc doesn’t insert forbidden elements in FictionBook titles.</p></section><section><title><p>Emphasized Strong Title</p></title></section></body></FictionBook>
diff --git a/test/fb2/titles.markdown b/test/fb2/titles.markdown
index cc3d0e0d0..1eaf2ccd5 100644
--- a/test/fb2/titles.markdown
+++ b/test/fb2/titles.markdown
@@ -4,7 +4,3 @@ This example tests if Pandoc doesn't insert forbidden elements in FictionBook ti
# *Emphasized* **Strong** Title
-# Title with\
-line break
-
-
diff --git a/test/latex-reader.native b/test/latex-reader.native
index f37f1b2ca..d481a714d 100644
--- a/test/latex-reader.native
+++ b/test/latex-reader.native
@@ -249,10 +249,10 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,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",SoftBreak,Str "unescaped",Space,Str "spaces:",Space,Str "a^b",Space,Str "c^d,",Space,Str "a",Math InlineMath "\\sim",Str "b",SoftBreak,Str "c",Math InlineMath "\\sim",Str "d."]
,HorizontalRule
,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 "Hello,"],Space,Str "said",Space,Str "the",Space,Str "spider.",Space,Quoted DoubleQuote [Str "\8198",Quoted SingleQuote [Str "Shelob"],Space,Str "is",Space,Str "my",Space,Str "name."]]
,Para [Quoted SingleQuote [Str "A"],Str ",",Space,Quoted SingleQuote [Str "B"],Str ",",Space,Str "and",Space,Quoted SingleQuote [Str "C"],Space,Str "are",Space,Str "letters."]
,Para [Quoted SingleQuote [Str "Oak,"],Space,Quoted SingleQuote [Str "elm,"],Space,Str "and",Space,Quoted SingleQuote [Str "beech"],Space,Str "are",Space,Str "names",Space,Str "of",Space,Str "trees.",Space,Str "So",Space,Str "is",Space,Quoted SingleQuote [Str "pine."]]
-,Para [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [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 [Quoted SingleQuote [Str "He",Space,Str "said,",Space,Quoted DoubleQuote [Str "I",Space,Str "want",Space,Str "to",Space,Str "go."],Str "\8198"],Space,Str "Were",Space,Str "you",Space,Str "alive",Space,Str "in",Space,Str "the",Space,Str "70\8217s?"]
,Para [Str "Here",Space,Str "is",Space,Str "some",Space,Str "quoted",Space,Quoted SingleQuote [Code ("",[],[]) "code"],Space,Str "and",Space,Str "a",SoftBreak,Quoted DoubleQuote [Link ("",[],[]) [Str "quoted",Space,Str "link"] ("http://example.com/?foo=1&bar=2","")],Str "."]
,Para [Str "Some",Space,Str "dashes:",Space,Str "one\8212two\8212three\8212four\8212five."]
,Para [Str "Dashes",Space,Str "between",Space,Str "numbers:",Space,Str "5\8211\&7,",Space,Str "255\8211\&66,",Space,Str "1987\8211\&1999."]
diff --git a/test/lhs-test.latex b/test/lhs-test.latex
index 3ca8f97c8..027ad3a0e 100644
--- a/test/lhs-test.latex
+++ b/test/lhs-test.latex
@@ -17,6 +17,12 @@
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
\usepackage[unicode=true]{hyperref}
\hypersetup{
@@ -61,12 +67,6 @@
\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}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
diff --git a/test/lhs-test.latex+lhs b/test/lhs-test.latex+lhs
index b0a58ac78..4aac4c7bb 100644
--- a/test/lhs-test.latex+lhs
+++ b/test/lhs-test.latex+lhs
@@ -17,6 +17,12 @@
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
\usepackage[unicode=true]{hyperref}
\hypersetup{
@@ -26,12 +32,6 @@
\usepackage{listings}
\newcommand{\passthrough}[1]{#1}
\lstnewenvironment{code}{\lstset{language=Haskell,basicstyle=\small\ttfamily}}{}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
diff --git a/test/markdown-reader-more.native b/test/markdown-reader-more.native
index baafb5334..1007dbac7 100644
--- a/test/markdown-reader-more.native
+++ b/test/markdown-reader-more.native
@@ -99,74 +99,74 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "Author",S
[[Plain [Str "col",Space,Str "1"]]
,[Plain [Str "col",Space,Str "2"]]
,[Plain [Str "col",Space,Str "3"]]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
,Para [Str "Headless"]
,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
[[]
,[]
,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
,Para [Str "With",Space,Str "alignments"]
,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
[[Plain [Str "col",Space,Str "1"]]
,[Plain [Str "col",Space,Str "2"]]
,[Plain [Str "col",Space,Str "3"]]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
,Para [Str "Headless",Space,Str "with",Space,Str "alignments"]
,Table [] [AlignRight,AlignLeft,AlignCenter] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
[[]
,[]
,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
,Para [Str "Spaces",Space,Str "at",Space,Str "ends",Space,Str "of",Space,Str "lines"]
,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
[[]
,[]
,[]]
- [[[Para [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
- ,[Para [Str "b",SoftBreak,Str "b",Space,Str "2"]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
- ,[[Para [Str "r2",Space,Str "d"]]
- ,[Para [Str "e"]]
- ,[Para [Str "f"]]]]
+ [[[Plain [Str "r1",Space,Str "a",SoftBreak,Str "r1",Space,Str "bis"]]
+ ,[Plain [Str "b",SoftBreak,Str "b",Space,Str "2"]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2"]]]
+ ,[[Plain [Str "r2",Space,Str "d"]]
+ ,[Plain [Str "e"]]
+ ,[Plain [Str "f"]]]]
,Para [Str "Multiple",Space,Str "blocks",Space,Str "in",Space,Str "a",Space,Str "cell"]
,Table [] [AlignDefault,AlignDefault,AlignDefault] [0.2638888888888889,0.16666666666666666,0.18055555555555555]
[[]
,[]
,[]]
[[[Header 1 ("col-1",[],[]) [Str "col",Space,Str "1"]
- ,Para [Str "col",Space,Str "1"]]
+ ,Plain [Str "col",Space,Str "1"]]
,[Header 1 ("col-2",[],[]) [Str "col",Space,Str "2"]
- ,Para [Str "col",Space,Str "2"]]
+ ,Plain [Str "col",Space,Str "2"]]
,[Header 1 ("col-3",[],[]) [Str "col",Space,Str "3"]
- ,Para [Str "col",Space,Str "3"]]]
+ ,Plain [Str "col",Space,Str "3"]]]
,[[Para [Str "r1",Space,Str "a"]
,Para [Str "r1",Space,Str "bis"]]
,[BulletList
[[Plain [Str "b"]]
,[Plain [Str "b",Space,Str "2"]]
,[Plain [Str "b",Space,Str "2"]]]]
- ,[Para [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
+ ,[Plain [Str "c",SoftBreak,Str "c",Space,Str "2",SoftBreak,Str "c",Space,Str "2"]]]]
,Para [Str "Empty",Space,Str "cells"]
,Table [] [AlignDefault,AlignDefault] [5.555555555555555e-2,5.555555555555555e-2]
[[]
diff --git a/test/tables-rstsubset.native b/test/tables-rstsubset.native
index d9bb9f2fb..8b7ccdf76 100644
--- a/test/tables-rstsubset.native
+++ b/test/tables-rstsubset.native
@@ -54,9 +54,9 @@
,[Plain [Str "1"]]]]
,Para [Str "Multiline",Space,Str "table",Space,Str "with",Space,Str "caption:"]
,Table [Str "Here\8217s",Space,Str "the",Space,Str "caption.",Space,Str "It",Space,Str "may",Space,Str "span",Space,Str "multiple",Space,Str "lines."] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
- [[Plain [Str "Centered",Space,Str "Header"]]
- ,[Plain [Str "Left",Space,Str "Aligned"]]
- ,[Plain [Str "Right",Space,Str "Aligned"]]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
,[Plain [Str "Default",Space,Str "aligned"]]]
[[[Plain [Str "First"]]
,[Plain [Str "row"]]
@@ -68,9 +68,9 @@
,[Plain [Str "Here\8217s",Space,Str "another",Space,Str "one.",SoftBreak,Str "Note",Space,Str "the",Space,Str "blank",Space,Str "line",SoftBreak,Str "between",Space,Str "rows."]]]]
,Para [Str "Multiline",Space,Str "table",Space,Str "without",Space,Str "caption:"]
,Table [] [AlignDefault,AlignDefault,AlignDefault,AlignDefault] [0.1375,0.125,0.15,0.325]
- [[Plain [Str "Centered",Space,Str "Header"]]
- ,[Plain [Str "Left",Space,Str "Aligned"]]
- ,[Plain [Str "Right",Space,Str "Aligned"]]
+ [[Plain [Str "Centered",SoftBreak,Str "Header"]]
+ ,[Plain [Str "Left",SoftBreak,Str "Aligned"]]
+ ,[Plain [Str "Right",SoftBreak,Str "Aligned"]]
,[Plain [Str "Default",Space,Str "aligned"]]]
[[[Plain [Str "First"]]
,[Plain [Str "row"]]
diff --git a/test/tables.muse b/test/tables.muse
index afdccd476..fdf20be49 100644
--- a/test/tables.muse
+++ b/test/tables.muse
@@ -1,46 +1,46 @@
Simple table with caption:
-Right || Left || Center || Default
-12 | 12 | 12 | 12
-123 | 123 | 123 | 123
-1 | 1 | 1 | 1
-|+ Demonstration of simple table syntax. +|
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+ |+ Demonstration of simple table syntax. +|
Simple table without caption:
-Right || Left || Center || Default
-12 | 12 | 12 | 12
-123 | 123 | 123 | 123
-1 | 1 | 1 | 1
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
Simple table indented two spaces:
-Right || Left || Center || Default
-12 | 12 | 12 | 12
-123 | 123 | 123 | 123
-1 | 1 | 1 | 1
-|+ Demonstration of simple table syntax. +|
+ Right || Left || Center || Default
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
+ |+ Demonstration of simple table syntax. +|
Multiline table with caption:
-Centered Header || Left Aligned || Right Aligned || Default aligned
-First | row | 12.0 | Example of a row that spans multiple lines.
-Second | row | 5.0 | Here’s another one. Note the blank line between rows.
-|+ Here’s the caption. It may span multiple lines. +|
+ Centered Header || Left Aligned || Right Aligned || Default aligned
+ First | row | 12.0 | Example of a row that spans multiple lines.
+ Second | row | 5.0 | Here’s another one. Note the blank line between rows.
+ |+ Here’s the caption. It may span multiple lines. +|
Multiline table without caption:
-Centered Header || Left Aligned || Right Aligned || Default aligned
-First | row | 12.0 | Example of a row that spans multiple lines.
-Second | row | 5.0 | Here’s another one. Note the blank line between rows.
+ Centered Header || Left Aligned || Right Aligned || Default aligned
+ First | row | 12.0 | Example of a row that spans multiple lines.
+ Second | row | 5.0 | Here’s another one. Note the blank line between rows.
Table without column headers:
-12 | 12 | 12 | 12
-123 | 123 | 123 | 123
-1 | 1 | 1 | 1
+ 12 | 12 | 12 | 12
+ 123 | 123 | 123 | 123
+ 1 | 1 | 1 | 1
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.
+ 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/test/testsuite.native b/test/testsuite.native
index fa234dfc2..0587bddb8 100644
--- a/test/testsuite.native
+++ b/test/testsuite.native
@@ -369,8 +369,6 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
,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 "."]
,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
diff --git a/test/testsuite.txt b/test/testsuite.txt
index f6b0a7c95..9413cc81a 100644
--- a/test/testsuite.txt
+++ b/test/testsuite.txt
@@ -621,16 +621,11 @@ Just a [URL](/url/).
## Reference
-Foo [bar] [a].
-
Foo [bar][a].
-Foo [bar]
-[a].
-
[a]: /url/
-With [embedded [brackets]] [b].
+With [embedded [brackets]][b].
[b] by itself should be a link.
@@ -659,9 +654,9 @@ Foo [biz](/url/ "Title with "quote" inside").
## With ampersands
-Here's a [link with an ampersand in the URL] [1].
+Here's a [link with an ampersand in the URL][1].
-Here's a link with an amersand in the link text: [AT&T] [2].
+Here's a link with an amersand in the link text: [AT&T][2].
Here's an [inline link](/script?foo=1&bar=2).
diff --git a/test/writer.asciidoc b/test/writer.asciidoc
index 2bf62e36f..639663743 100644
--- a/test/writer.asciidoc
+++ b/test/writer.asciidoc
@@ -600,10 +600,6 @@ Reference
Foo link:/url/[bar].
-Foo link:/url/[bar].
-
-Foo link:/url/[bar].
-
With link:/url/[embedded [brackets]].
link:/url/[b] by itself should be a link.
diff --git a/test/writer.context b/test/writer.context
index 04df66178..9884c82c9 100644
--- a/test/writer.context
+++ b/test/writer.context
@@ -6,19 +6,28 @@
style=,
color=,
contrastcolor=]
+
% make chapter, section bookmarks visible when opening document
\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
\setupinteractionscreen[option=bookmark]
\setuptagging[state=start]
+
% use microtypography
\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
\setupalign[hz,hanging]
\setupitaliccorrection[global, always]
+
\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][Latin Modern Roman]
+\definefontfamily[mainface][mm][Latin Modern Math]
+\definefontfamily[mainface][ss][Latin Modern Sans]
+\definefontfamily[mainface][tt][Latin Modern Typewriter][features=none]
+\setupbodyfont[mainface]
+
\setupwhitespace[medium]
\setuphead[chapter] [style=\tfd,header=empty]
@@ -778,19 +787,15 @@ Just a \useURL[url4][/url/][][URL]\from[url4].
Foo \useURL[url13][/url/][][bar]\from[url13].
-Foo \useURL[url14][/url/][][bar]\from[url14].
-
-Foo \useURL[url15][/url/][][bar]\from[url15].
-
-With \useURL[url16][/url/][][embedded {[}brackets{]}]\from[url16].
+With \useURL[url14][/url/][][embedded {[}brackets{]}]\from[url14].
-\useURL[url17][/url/][][b]\from[url17] by itself should be a link.
+\useURL[url15][/url/][][b]\from[url15] by itself should be a link.
-Indented \useURL[url18][/url][][once]\from[url18].
+Indented \useURL[url16][/url][][once]\from[url16].
-Indented \useURL[url19][/url][][twice]\from[url19].
+Indented \useURL[url17][/url][][twice]\from[url17].
-Indented \useURL[url20][/url][][thrice]\from[url20].
+Indented \useURL[url18][/url][][thrice]\from[url18].
This should {[}not{]}{[}{]} be a link.
@@ -798,41 +803,41 @@ This should {[}not{]}{[}{]} be a link.
[not]: /url
\stoptyping
-Foo \useURL[url21][/url/][][bar]\from[url21].
+Foo \useURL[url19][/url/][][bar]\from[url19].
-Foo \useURL[url22][/url/][][biz]\from[url22].
+Foo \useURL[url20][/url/][][biz]\from[url20].
\subsection[with-ampersands]{With ampersands}
-Here's a \useURL[url23][http://example.com/?foo=1&bar=2][][link with an
-ampersand in the URL]\from[url23].
+Here's a \useURL[url21][http://example.com/?foo=1&bar=2][][link with an
+ampersand in the URL]\from[url21].
Here's a link with an amersand in the link text:
-\useURL[url24][http://att.com/][][AT&T]\from[url24].
+\useURL[url22][http://att.com/][][AT&T]\from[url22].
-Here's an \useURL[url25][/script?foo=1&bar=2][][inline link]\from[url25].
+Here's an \useURL[url23][/script?foo=1&bar=2][][inline link]\from[url23].
-Here's an \useURL[url26][/script?foo=1&bar=2][][inline link in pointy
-braces]\from[url26].
+Here's an \useURL[url24][/script?foo=1&bar=2][][inline link in pointy
+braces]\from[url24].
\subsection[autolinks]{Autolinks}
-With an ampersand: \useURL[url27][http://example.com/?foo=1&bar=2]\from[url27]
+With an ampersand: \useURL[url25][http://example.com/?foo=1&bar=2]\from[url25]
\startitemize[packed]
\item
In a list?
\item
- \useURL[url28][http://example.com/]\from[url28]
+ \useURL[url26][http://example.com/]\from[url26]
\item
It should.
\stopitemize
An e-mail address:
-\useURL[url29][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url29]
+\useURL[url27][mailto:nobody@nowhere.net][][nobody@nowhere.net]\from[url27]
\startblockquote
-Blockquoted: \useURL[url30][http://example.com/]\from[url30]
+Blockquoted: \useURL[url28][http://example.com/]\from[url28]
\stopblockquote
Auto-links should not occur here: \type{<http://example.com/>}
@@ -871,7 +876,7 @@ Here is a footnote reference,\footnote{Here is the footnote. It can go
indent the first line of each block.\stopbuffer\footnote{\getbuffer} This
should {\em not} be a footnote reference, because it contains a space.{[}^my
note{]} Here is an inline note.\footnote{This is {\em easier} to type. Inline
- notes may contain \useURL[url31][http://google.com][][links]\from[url31] and
+ notes may contain \useURL[url29][http://google.com][][links]\from[url29] and
\type{]} verbatim characters, as well as {[}bracketed text{]}.}
\startblockquote
diff --git a/test/writer.docbook4 b/test/writer.docbook4
index eee19cdd9..163255974 100644
--- a/test/writer.docbook4
+++ b/test/writer.docbook4
@@ -1249,12 +1249,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{
Foo <ulink url="/url/">bar</ulink>.
</para>
<para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
- Foo <ulink url="/url/">bar</ulink>.
- </para>
- <para>
With <ulink url="/url/">embedded [brackets]</ulink>.
</para>
<para>
diff --git a/test/writer.docbook5 b/test/writer.docbook5
index 07ca0f827..992cd8b63 100644
--- a/test/writer.docbook5
+++ b/test/writer.docbook5
@@ -1224,12 +1224,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{
Foo <link xlink:href="/url/">bar</link>.
</para>
<para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
- Foo <link xlink:href="/url/">bar</link>.
- </para>
- <para>
With <link xlink:href="/url/">embedded [brackets]</link>.
</para>
<para>
diff --git a/test/writer.dokuwiki b/test/writer.dokuwiki
index 79fcdde8a..4ba1b7054 100644
--- a/test/writer.dokuwiki
+++ b/test/writer.dokuwiki
@@ -556,10 +556,6 @@ Just a [[url/|URL]].
Foo [[url/|bar]].
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
With [[url/|embedded [brackets]]].
[[url/|b]] by itself should be a link.
diff --git a/test/writer.fb2 b/test/writer.fb2
index 0412c8cf4..63d0bdfbf 100644
--- a/test/writer.fb2
+++ b/test/writer.fb2
@@ -1,3 +1,1013 @@
<?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>This is <emphasis>emphasized</emphasis>And this is <strong>strong</strong><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><p>Multiline:</p><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><p>Code:</p><empty-line /><p><code>&lt;hr /&gt;</code></p><empty-line /><p>Hr’s:</p><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>——————————</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>
-
+<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>This is <emphasis>emphasized</emphasis>And this is <strong>strong</strong>
+<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>
+<p>Multiline:</p>
+<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>
+<p>Code:</p>
+<empty-line />
+<p>
+<code>&lt;hr /&gt;</code>
+</p>
+<empty-line />
+<p>Hr’s:</p>
+<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>——————————</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>With embedded [brackets]<a l:href="#l13" type="note">
+<sup>[13]</sup>
+</a>.</p>
+<p>b<a l:href="#l14" type="note">
+<sup>[14]</sup>
+</a> by itself should be a link.</p>
+<p>Indented once<a l:href="#l15" type="note">
+<sup>[15]</sup>
+</a>.</p>
+<p>Indented twice<a l:href="#l16" type="note">
+<sup>[16]</sup>
+</a>.</p>
+<p>Indented thrice<a l:href="#l17" type="note">
+<sup>[17]</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="#l18" type="note">
+<sup>[18]</sup>
+</a>.</p>
+<p>Foo biz<a l:href="#l19" type="note">
+<sup>[19]</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="#l20" type="note">
+<sup>[20]</sup>
+</a>.</p>
+<p>Here’s a link with an amersand in the link text: AT&amp;T<a l:href="#l21" type="note">
+<sup>[21]</sup>
+</a>.</p>
+<p>Here’s an inline link<a l:href="#l22" type="note">
+<sup>[22]</sup>
+</a>.</p>
+<p>Here’s an inline link in pointy braces<a l:href="#l23" type="note">
+<sup>[23]</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="#l24" type="note">
+<sup>[24]</sup>
+</a>
+</p>
+<p>• In a list?</p>
+<p>• http://example.com/<a l:href="#l25" type="note">
+<sup>[25]</sup>
+</a>
+</p>
+<p>• It should.</p>
+<p>An e-mail address: nobody@nowhere.net<a l:href="#l26" type="note">
+<sup>[26]</sup>
+</a>
+</p>
+<cite>
+<p>Blockquoted: http://example.com/<a l:href="#l27" type="note">
+<sup>[27]</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="#n28" type="note">
+<sup>[28]</sup>
+</a> and another.<a l:href="#n29" type="note">
+<sup>[29]</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="#n30" type="note">
+<sup>[30]</sup>
+</a>
+</p>
+<cite>
+<p>Notes can go in quotes.<a l:href="#n31" type="note">
+<sup>[31]</sup>
+</a>
+</p>
+</cite>
+<p> 1. And in list items.<a l:href="#n32" type="note">
+<sup>[32]</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>Title with &quot;quotes&quot; inside: <code>/url/</code>
+</p>
+</section>
+<section id="l19">
+<title>
+<p>19</p>
+</title>
+<p>Title with &quot;quote&quot; inside: <code>/url/</code>
+</p>
+</section>
+<section id="l20">
+<title>
+<p>20</p>
+</title>
+<p>
+<code>http://example.com/?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l21">
+<title>
+<p>21</p>
+</title>
+<p>AT&amp;T: <code>http://att.com/</code>
+</p>
+</section>
+<section id="l22">
+<title>
+<p>22</p>
+</title>
+<p>
+<code>/script?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l23">
+<title>
+<p>23</p>
+</title>
+<p>
+<code>/script?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l24">
+<title>
+<p>24</p>
+</title>
+<p>
+<code>http://example.com/?foo=1&amp;bar=2</code>
+</p>
+</section>
+<section id="l25">
+<title>
+<p>25</p>
+</title>
+<p>
+<code>http://example.com/</code>
+</p>
+</section>
+<section id="l26">
+<title>
+<p>26</p>
+</title>
+<p>
+<code>mailto:nobody@nowhere.net</code>
+</p>
+</section>
+<section id="l27">
+<title>
+<p>27</p>
+</title>
+<p>
+<code>http://example.com/</code>
+</p>
+</section>
+<section id="n28">
+<title>
+<p>28</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="n29">
+<title>
+<p>29</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="n30">
+<title>
+<p>30</p>
+</title>
+<p>This is <emphasis>easier</emphasis> to type. Inline notes may contain links<a l:href="#l30" type="note">
+<sup>[30]</sup>
+</a> and <code>]</code> verbatim characters, as well as [bracketed text].</p>
+</section>
+<section id="n31">
+<title>
+<p>31</p>
+</title>
+<p>In quote.</p>
+</section>
+<section id="n32">
+<title>
+<p>32</p>
+</title>
+<p>In list.</p>
+</section>
+</body>
+</FictionBook>
diff --git a/test/writer.haddock b/test/writer.haddock
index 0772331e3..7f783abd1 100644
--- a/test/writer.haddock
+++ b/test/writer.haddock
@@ -560,10 +560,6 @@ Just a </url/ URL>.
Foo </url/ bar>.
-Foo </url/ bar>.
-
-Foo </url/ bar>.
-
With </url/ embedded [brackets]>.
</url/ b> by itself should be a link.
diff --git a/test/writer.html4 b/test/writer.html4
index bac16b14c..89cf07685 100644
--- a/test/writer.html4
+++ b/test/writer.html4
@@ -486,8 +486,6 @@ Blah
<p><a href="">Empty</a>.</p>
<h2 id="reference">Reference</h2>
<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
<p>With <a href="/url/">embedded [brackets]</a>.</p>
<p><a href="/url/">b</a> by itself should be a link.</p>
<p>Indented <a href="/url">once</a>.</p>
diff --git a/test/writer.html5 b/test/writer.html5
index ee921766c..6762f8198 100644
--- a/test/writer.html5
+++ b/test/writer.html5
@@ -489,8 +489,6 @@ Blah
<p><a href="">Empty</a>.</p>
<h2 id="reference">Reference</h2>
<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
-<p>Foo <a href="/url/">bar</a>.</p>
<p>With <a href="/url/">embedded [brackets]</a>.</p>
<p><a href="/url/">b</a> by itself should be a link.</p>
<p>Indented <a href="/url">once</a>.</p>
diff --git a/test/writer.icml b/test/writer.icml
index b498f568b..6e070e264 100644
--- a/test/writer.icml
+++ b/test/writer.icml
@@ -2566,37 +2566,9 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Br />
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-14" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>Foo </Content>
- </CharacterStyleRange>
- <HyperlinkTextSource Self="htss-15" Name="" Hidden="false">
- <CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
- <Content>bar</Content>
- </CharacterStyleRange>
- </HyperlinkTextSource>
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Content>.</Content>
- </CharacterStyleRange>
-</ParagraphStyleRange>
-<Br />
-<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>With </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-16" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-14" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>embedded [brackets]</Content>
</CharacterStyleRange>
@@ -2607,7 +2579,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
</ParagraphStyleRange>
<Br />
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Paragraph">
- <HyperlinkTextSource Self="htss-17" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-15" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>b</Content>
</CharacterStyleRange>
@@ -2621,7 +2593,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Indented </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-18" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-16" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>once</Content>
</CharacterStyleRange>
@@ -2635,7 +2607,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Indented </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-19" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-17" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>twice</Content>
</CharacterStyleRange>
@@ -2649,7 +2621,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Indented </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-20" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-18" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>thrice</Content>
</CharacterStyleRange>
@@ -2675,7 +2647,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Foo </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-21" Name="Title with &quot;quotes&quot; inside" Hidden="false">
+ <HyperlinkTextSource Self="htss-19" Name="Title with &quot;quotes&quot; inside" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>bar</Content>
</CharacterStyleRange>
@@ -2689,7 +2661,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Foo </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-22" Name="Title with &quot;quote&quot; inside" Hidden="false">
+ <HyperlinkTextSource Self="htss-20" Name="Title with &quot;quote&quot; inside" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>biz</Content>
</CharacterStyleRange>
@@ -2709,7 +2681,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Here’s a </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-23" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-21" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>link with an ampersand in the URL</Content>
</CharacterStyleRange>
@@ -2723,7 +2695,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Here’s a link with an amersand in the link text: </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-24" Name="AT&amp;T" Hidden="false">
+ <HyperlinkTextSource Self="htss-22" Name="AT&amp;T" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>AT&amp;T</Content>
</CharacterStyleRange>
@@ -2737,7 +2709,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Here’s an </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-25" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-23" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>inline link</Content>
</CharacterStyleRange>
@@ -2751,7 +2723,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Here’s an </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-26" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-24" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>inline link in pointy braces</Content>
</CharacterStyleRange>
@@ -2771,7 +2743,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>With an ampersand: </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-27" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-25" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>http://example.com/?foo=1&amp;bar=2</Content>
</CharacterStyleRange>
@@ -2785,7 +2757,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
</ParagraphStyleRange>
<Br />
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/BulList">
- <HyperlinkTextSource Self="htss-28" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-26" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>http://example.com/</Content>
</CharacterStyleRange>
@@ -2802,7 +2774,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>An e-mail address: </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-29" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-27" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>nobody@nowhere.net</Content>
</CharacterStyleRange>
@@ -2813,7 +2785,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content>Blockquoted: </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-30" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-28" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>http://example.com/</Content>
</CharacterStyleRange>
@@ -2861,20 +2833,20 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Br />
<ParagraphStyleRange AppliedParagraphStyle="ParagraphStyle/Figure">
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1.00000 0 0 1.00000 75.00000 -75.00000">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 75 -75">
<Properties>
<PathGeometry>
<GeometryPathType PathOpen="false">
<PathPointArray>
- <PathPointType Anchor="-75.00000 -75.00000" LeftDirection="-75.00000 -75.00000" RightDirection="-75.00000 -75.00000" />
- <PathPointType Anchor="-75.00000 75.00000" LeftDirection="-75.00000 75.00000" RightDirection="-75.00000 75.00000" />
- <PathPointType Anchor="75.00000 75.00000" LeftDirection="75.00000 75.00000" RightDirection="75.00000 75.00000" />
- <PathPointType Anchor="75.00000 -75.00000" LeftDirection="75.00000 -75.00000" RightDirection="75.00000 -75.00000" />
+ <PathPointType Anchor="-75 -75" LeftDirection="-75 -75" RightDirection="-75 -75" />
+ <PathPointType Anchor="-75 75" LeftDirection="-75 75" RightDirection="-75 75" />
+ <PathPointType Anchor="75 75" LeftDirection="75 75" RightDirection="75 75" />
+ <PathPointType Anchor="75 -75" LeftDirection="75 -75" RightDirection="75 -75" />
</PathPointArray>
</GeometryPathType>
</PathGeometry>
</Properties>
- <Image Self="ue6" ItemTransform="1.00000 0 0 1.00000 -75.00000 -75.00000">
+ <Image Self="ue6" ItemTransform="1 0 0 1 -75 -75">
<Properties>
<Profile type="string">
$ID/Embedded
@@ -2897,20 +2869,20 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<Content>Here is a movie </Content>
</CharacterStyleRange>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
- <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1.00000 0 0 1.00000 10.00000 -11.00000">
+ <Rectangle Self="uec" StrokeWeight="0" ItemTransform="1 0 0 1 10 -11">
<Properties>
<PathGeometry>
<GeometryPathType PathOpen="false">
<PathPointArray>
- <PathPointType Anchor="-10.00000 -11.00000" LeftDirection="-10.00000 -11.00000" RightDirection="-10.00000 -11.00000" />
- <PathPointType Anchor="-10.00000 11.00000" LeftDirection="-10.00000 11.00000" RightDirection="-10.00000 11.00000" />
- <PathPointType Anchor="10.00000 11.00000" LeftDirection="10.00000 11.00000" RightDirection="10.00000 11.00000" />
- <PathPointType Anchor="10.00000 -11.00000" LeftDirection="10.00000 -11.00000" RightDirection="10.00000 -11.00000" />
+ <PathPointType Anchor="-10 -11" LeftDirection="-10 -11" RightDirection="-10 -11" />
+ <PathPointType Anchor="-10 11" LeftDirection="-10 11" RightDirection="-10 11" />
+ <PathPointType Anchor="10 11" LeftDirection="10 11" RightDirection="10 11" />
+ <PathPointType Anchor="10 -11" LeftDirection="10 -11" RightDirection="10 -11" />
</PathPointArray>
</GeometryPathType>
</PathGeometry>
</Properties>
- <Image Self="ue6" ItemTransform="1.00000 0 0 1.00000 -10.00000 -11.00000">
+ <Image Self="ue6" ItemTransform="1 0 0 1 -10 -11">
<Properties>
<Profile type="string">
$ID/Embedded
@@ -3025,7 +2997,7 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
<CharacterStyleRange AppliedCharacterStyle="$ID/NormalCharacterStyle">
<Content> to type. Inline notes may contain </Content>
</CharacterStyleRange>
- <HyperlinkTextSource Self="htss-31" Name="" Hidden="false">
+ <HyperlinkTextSource Self="htss-29" Name="" Hidden="false">
<CharacterStyleRange AppliedCharacterStyle="CharacterStyle/Link">
<Content>links</Content>
</CharacterStyleRange>
@@ -3098,118 +3070,104 @@ These should not be escaped: \$ \\ \&gt; \[ \{</Content>
</Story>
<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">
+ <Hyperlink Self="uf-29" Name="http://google.com" Source="htss-29" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//google.com</Destination>
</Properties>
</Hyperlink>
<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">
+ <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%3a//example.com/</Destination>
</Properties>
</Hyperlink>
<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">
+ <Hyperlink Self="uf-27" Name="mailto:nobody@nowhere.net" Source="htss-27" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/mailto%3anobody@nowhere.net</Destination>
</Properties>
</Hyperlink>
<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">
+ <Hyperlink Self="uf-26" Name="http://example.com/" Source="htss-26" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//example.com/</Destination>
</Properties>
</Hyperlink>
<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">
+ <Hyperlink Self="uf-25" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-25" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<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" />
- <Hyperlink Self="uf-26" Name="/script?foo=1&amp;bar=2" Source="htss-26" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-24" Name="/script?foo=1&amp;bar=2" Source="htss-24" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//script?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" />
- <Hyperlink Self="uf-25" Name="/script?foo=1&amp;bar=2" Source="htss-25" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-23" Name="/script?foo=1&amp;bar=2" Source="htss-23" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//script?foo=1&amp;bar=2</Destination>
</Properties>
</Hyperlink>
<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">
+ <Hyperlink Self="uf-22" Name="http://att.com/" Source="htss-22" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination/http%3a//att.com/</Destination>
</Properties>
</Hyperlink>
<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">
+ <Hyperlink Self="uf-21" Name="http://example.com/?foo=1&amp;bar=2" Source="htss-21" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<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" />
- <Hyperlink Self="uf-22" Name="/url/" Source="htss-22" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-20" Name="/url/" Source="htss-20" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//url/</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-21" Name="/url/" Source="htss-21" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-19" Name="/url/" Source="htss-19" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//url/</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-20" Name="/url" Source="htss-20" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-18" Name="/url" Source="htss-18" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//url</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-19" Name="/url" Source="htss-19" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-17" Name="/url" Source="htss-17" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//url</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url" Name="link" DestinationURL="/url" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-18" Name="/url" Source="htss-18" Visible="true" DestinationUniqueKey="1">
+ <Hyperlink Self="uf-16" Name="/url" Source="htss-16" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
<Destination type="object">HyperlinkURLDestination//url</Destination>
</Properties>
</Hyperlink>
<HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-17" Name="/url/" Source="htss-17" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
- <Hyperlink Self="uf-16" Name="/url/" Source="htss-16" Visible="true" DestinationUniqueKey="1">
- <Properties>
- <BorderColor type="enumeration">Black</BorderColor>
- <Destination type="object">HyperlinkURLDestination//url/</Destination>
- </Properties>
- </Hyperlink>
- <HyperlinkURLDestination Self="HyperlinkURLDestination//url/" Name="link" DestinationURL="/url/" DestinationUniqueKey="1" />
<Hyperlink Self="uf-15" Name="/url/" Source="htss-15" Visible="true" DestinationUniqueKey="1">
<Properties>
<BorderColor type="enumeration">Black</BorderColor>
diff --git a/test/writer.jats b/test/writer.jats
index 07fe24d73..3cb5050c2 100644
--- a/test/writer.jats
+++ b/test/writer.jats
@@ -1267,12 +1267,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{</preformat>
Foo <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
</p>
<p>
- Foo <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
- </p>
- <p>
- Foo <ext-link ext-link-type="uri" xlink:href="/url/">bar</ext-link>.
- </p>
- <p>
With <ext-link ext-link-type="uri" xlink:href="/url/">embedded
[brackets]</ext-link>.
</p>
diff --git a/test/writer.latex b/test/writer.latex
index f88621a28..207e30569 100644
--- a/test/writer.latex
+++ b/test/writer.latex
@@ -17,6 +17,12 @@
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
\usepackage{fancyvrb}
\usepackage[unicode=true]{hyperref}
@@ -39,12 +45,6 @@
\usepackage[normalem]{ulem}
% avoid problems with \sout in headers with hyperref:
\pdfstringdefDisableCommands{\renewcommand{\sout}{}}
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\setlength{\parindent}{0pt}
-\setlength{\parskip}{6pt plus 2pt minus 1pt}
-}
\setlength{\emergencystretch}{3em} % prevent overfull lines
\providecommand{\tightlist}{%
\setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
@@ -877,10 +877,6 @@ Just a \href{/url/}{URL}.
Foo \href{/url/}{bar}.
-Foo \href{/url/}{bar}.
-
-Foo \href{/url/}{bar}.
-
With \href{/url/}{embedded {[}brackets{]}}.
\href{/url/}{b} by itself should be a link.
diff --git a/test/writer.man b/test/writer.man
index 907fb4878..f6d0deb92 100644
--- a/test/writer.man
+++ b/test/writer.man
@@ -677,10 +677,6 @@ Empty ().
.PP
Foo bar (/url/).
.PP
-Foo bar (/url/).
-.PP
-Foo bar (/url/).
-.PP
With embedded [brackets] (/url/).
.PP
b (/url/) by itself should be a link.
diff --git a/test/writer.markdown b/test/writer.markdown
index 3fe0f4b3e..d41030785 100644
--- a/test/writer.markdown
+++ b/test/writer.markdown
@@ -647,10 +647,6 @@ Reference
Foo [bar](/url/).
-Foo [bar](/url/).
-
-Foo [bar](/url/).
-
With [embedded \[brackets\]](/url/).
[b](/url/) by itself should be a link.
diff --git a/test/writer.mediawiki b/test/writer.mediawiki
index a0dc15fae..968eef388 100644
--- a/test/writer.mediawiki
+++ b/test/writer.mediawiki
@@ -571,10 +571,6 @@ Just a [[url/|URL]].
Foo [[url/|bar]].
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
With [[url/|embedded [brackets]]].
[[url/|b]] by itself should be a link.
diff --git a/test/writer.ms b/test/writer.ms
index 617ccc752..7e079c55d 100644
--- a/test/writer.ms
+++ b/test/writer.ms
@@ -835,16 +835,6 @@ Foo \c
-- "bar"
\&.
.PP
-Foo \c
-.pdfhref W -D "/url/" -A "\c" \
- -- "bar"
-\&.
-.PP
-Foo \c
-.pdfhref W -D "/url/" -A "\c" \
- -- "bar"
-\&.
-.PP
With \c
.pdfhref W -D "/url/" -A "\c" \
-- "embedded [brackets]"
diff --git a/test/writer.muse b/test/writer.muse
index c19cb8ab2..41d1c9a5b 100644
--- a/test/writer.muse
+++ b/test/writer.muse
@@ -9,47 +9,30 @@ markdown test suite.
* Headers
-#headers
-
** Level 2 with an [[/url][embedded link]]
-#level-2-with-an-embedded-link
-
*** Level 3 with <em>emphasis</em>
-#level-3-with-emphasis
-
**** Level 4
-#level-4
-
***** Level 5
-#level-5
-
* Level 1
-#level-1
-
** Level 2 with <em>emphasis</em>
-#level-2-with-emphasis
-
*** Level 3
-#level-3
with no blank line
** Level 2
-#level-2
with no blank line
----
* Paragraphs
-#paragraphs
Here’s a regular paragraph.
In Markdown 1.0.0 and earlier. Version 8. This line turns into a list item.
@@ -65,7 +48,6 @@ here.
* Block Quotes
-#block-quotes
E-mail style:
<quote>
@@ -105,7 +87,6 @@ And a following paragraph.
* Code Blocks
-#code-blocks
Code:
<example>
@@ -130,11 +111,8 @@ These should not be escaped: \$ \\ \> \[ \{
* Lists
-#lists
-
** Unordered
-#unordered
Asterisks tight:
- asterisk 1
@@ -173,7 +151,6 @@ Minuses loose:
** Ordered
-#ordered
Tight:
1. First
@@ -208,7 +185,6 @@ Multiple paragraphs:
** Nested
-#nested
- Tab
- Tab
- Tab
@@ -234,7 +210,6 @@ Same thing but with paragraphs:
** Tabs and spaces
-#tabs-and-spaces
- this is a list item indented with tabs
- this is a list item indented with spaces
@@ -243,7 +218,6 @@ Same thing but with paragraphs:
** Fancy list markers
-#fancy-list-markers
2. begins with 2
3. and now 3
@@ -277,7 +251,6 @@ B. Williams
* Definition Lists
-#definition-lists
Tight using spaces:
apple :: red fruit
@@ -339,7 +312,6 @@ Blank line after term, indented marker, alternate markers:
* HTML Blocks
-#html-blocks
Simple block on one line:
fooAnd nested without indentation:
@@ -489,7 +461,6 @@ Hr’s:
* Inline Markup
-#inline-markup
This is <em>emphasized</em>, and so <em>is this</em>.
This is <strong>strong</strong>, and so <strong>is this</strong>.
@@ -521,7 +492,6 @@ spaces: a^b c^d, a~b c~d.
* Smart quotes, ellipses, dashes
-#smart-quotes-ellipses-dashes
"Hello," said the spider. "'Shelob' is my name."
'A', 'B', and 'C' are letters.
@@ -543,7 +513,6 @@ Ellipses…and…and….
* LaTeX
-#latex
- <literal style="tex">\cite[22-23]{smith.1899}</literal>
- 2 + 2 <verbatim>=</verbatim> 4
- <em>x</em> ∈ <em>y</em>
@@ -578,7 +547,6 @@ Cat & 1 \\ \hline
* Special Characters
-#special-characters
Here is some unicode:
- I hat: Î
@@ -633,11 +601,8 @@ Minus: -
* Links
-#links
-
** Explicit
-#explicit
Just a [[/url/][URL]].
[[/url/][URL and title]].
@@ -658,11 +623,6 @@ Just a [[/url/][URL]].
** Reference
-#reference
-Foo [[/url/][bar]].
-
-Foo [[/url/][bar]].
-
Foo [[/url/][bar]].
With [[/url/][embedded <verbatim>[brackets]</verbatim>]].
@@ -687,7 +647,6 @@ Foo [[/url/][biz]].
** With ampersands
-#with-ampersands
Here’s a [[http://example.com/?foo=1&bar=2][link with an ampersand in the
URL]].
@@ -699,7 +658,6 @@ Here’s an [[/script?foo=1&bar=2][inline link in pointy braces]].
** Autolinks
-#autolinks
With an ampersand: [[http://example.com/?foo=1&bar=2]]
- In a list?
@@ -723,7 +681,6 @@ or here: <http://example.com/>
* Images
-#images
From "Voyage dans la Lune" by Georges Melies (1902):
[[lalune.jpg][Voyage dans la Lune]]
@@ -734,7 +691,6 @@ Here is a movie [[movie.jpg][movie]] icon.
* Footnotes
-#footnotes
Here is a footnote reference,[1] and another.[2] This should <em>not</em> be a
footnote reference, because it contains a <verbatim>space.[^my</verbatim>
<verbatim>note]</verbatim> Here is an inline note.[3]
diff --git a/test/writer.native b/test/writer.native
index fa234dfc2..0587bddb8 100644
--- a/test/writer.native
+++ b/test/writer.native
@@ -369,8 +369,6 @@ Pandoc (Meta {unMeta = fromList [("author",MetaList [MetaInlines [Str "John",Spa
,Para [Link ("",[],[]) [Str "Empty"] ("",""),Str "."]
,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 "."]
,Para [Str "With",Space,Link ("",[],[]) [Str "embedded",Space,Str "[brackets]"] ("/url/",""),Str "."]
,Para [Link ("",[],[]) [Str "b"] ("/url/",""),Space,Str "by",Space,Str "itself",Space,Str "should",Space,Str "be",Space,Str "a",Space,Str "link."]
,Para [Str "Indented",Space,Link ("",[],[]) [Str "once"] ("/url",""),Str "."]
diff --git a/test/writer.opendocument b/test/writer.opendocument
index 86d88ee27..77c79d13c 100644
--- a/test/writer.opendocument
+++ b/test/writer.opendocument
@@ -1434,10 +1434,6 @@ link</text:span></text:a></text:p>
<text:h text:style-name="Heading_20_2" text:outline-level="2">Reference</text:h>
<text:p text:style-name="First_20_paragraph">Foo
<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
-<text:p text:style-name="Text_20_body">Foo
-<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">bar</text:span></text:a>.</text:p>
<text:p text:style-name="Text_20_body">With
<text:a xlink:type="simple" xlink:href="/url/" office:name=""><text:span text:style-name="Definition">embedded
[brackets]</text:span></text:a>.</text:p>
diff --git a/test/writer.opml b/test/writer.opml
index 51b0cb2d5..4e67652d2 100644
--- a/test/writer.opml
+++ b/test/writer.opml
@@ -57,7 +57,7 @@
<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]().">
</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;).">
+ <outline text="Reference" _note="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).">
</outline>
diff --git a/test/writer.org b/test/writer.org
index 96db87449..1ae0ca8f3 100644
--- a/test/writer.org
+++ b/test/writer.org
@@ -737,10 +737,6 @@ Just a [[/url/][URL]].
Foo [[/url/][bar]].
-Foo [[/url/][bar]].
-
-Foo [[/url/][bar]].
-
With [[/url/][embedded [brackets]]].
[[/url/][b]] by itself should be a link.
diff --git a/test/writer.plain b/test/writer.plain
index 175efb608..031c4a3e6 100644
--- a/test/writer.plain
+++ b/test/writer.plain
@@ -594,10 +594,6 @@ Reference
Foo bar.
-Foo bar.
-
-Foo bar.
-
With embedded [brackets].
b by itself should be a link.
diff --git a/test/writer.rst b/test/writer.rst
index 1aeeacacb..e81e79f3f 100644
--- a/test/writer.rst
+++ b/test/writer.rst
@@ -75,6 +75,8 @@ E-mail style:
This is a block quote. It is pretty short.
+..
+
Code in a block quote:
::
@@ -92,6 +94,8 @@ E-mail style:
nested
+ ..
+
nested
This should not be a block quote: 2 > 1.
@@ -342,6 +346,8 @@ Multiple blocks with italics:
{ orange code block }
+ ..
+
orange block quote
Multiple definitions, tight:
@@ -777,10 +783,6 @@ Reference
Foo `bar </url/>`__.
-Foo `bar </url/>`__.
-
-Foo `bar </url/>`__.
-
With `embedded [brackets] </url/>`__.
`b </url/>`__ by itself should be a link.
diff --git a/test/writer.rtf b/test/writer.rtf
index a79ae6fb5..c67c67a83 100644
--- a/test/writer.rtf
+++ b/test/writer.rtf
@@ -350,14 +350,6 @@ Empty
bar
}}}
.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
-{\pard \ql \f0 \sa180 \li0 \fi0 Foo {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
-bar
-}}}
-.\par}
{\pard \ql \f0 \sa180 \li0 \fi0 With {\field{\*\fldinst{HYPERLINK "/url/"}}{\fldrslt{\ul
embedded [brackets]
}}}
diff --git a/test/writer.tei b/test/writer.tei
index 986240c86..ecbe92e33 100644
--- a/test/writer.tei
+++ b/test/writer.tei
@@ -754,8 +754,6 @@ These should not be escaped: \$ \\ \&gt; \[ \{
<div type="level2" id="reference">
<head>Reference</head>
<p>Foo <ref target="/url/">bar</ref>.</p>
- <p>Foo <ref target="/url/">bar</ref>.</p>
- <p>Foo <ref target="/url/">bar</ref>.</p>
<p>With <ref target="/url/">embedded [brackets]</ref>.</p>
<p><ref target="/url/">b</ref> by itself should be a link.</p>
<p>Indented <ref target="/url">once</ref>.</p>
diff --git a/test/writer.texinfo b/test/writer.texinfo
index ca87da1a9..f5727d96d 100644
--- a/test/writer.texinfo
+++ b/test/writer.texinfo
@@ -939,10 +939,6 @@ Just a @uref{/url/,URL}.
@anchor{#reference}
Foo @uref{/url/,bar}.
-Foo @uref{/url/,bar}.
-
-Foo @uref{/url/,bar}.
-
With @uref{/url/,embedded [brackets]}.
@uref{/url/,b} by itself should be a link.
diff --git a/test/writer.textile b/test/writer.textile
index 293418ed5..d19b698f9 100644
--- a/test/writer.textile
+++ b/test/writer.textile
@@ -623,10 +623,6 @@ h2(#reference). Reference
Foo "bar":/url/.
-Foo "bar":/url/.
-
-Foo "bar":/url/.
-
With "embedded [brackets]":/url/.
"b":/url/ by itself should be a link.
diff --git a/test/writer.zimwiki b/test/writer.zimwiki
index 7a15bad9d..91f018b52 100644
--- a/test/writer.zimwiki
+++ b/test/writer.zimwiki
@@ -538,10 +538,6 @@ Just a [[url/|URL]].
Foo [[url/|bar]].
-Foo [[url/|bar]].
-
-Foo [[url/|bar]].
-
With [[url/|embedded [brackets]]].
[[url/|b]] by itself should be a link.
diff --git a/test/writers-lang-and-dir.context b/test/writers-lang-and-dir.context
index 66dab9ead..250ee8c59 100644
--- a/test/writers-lang-and-dir.context
+++ b/test/writers-lang-and-dir.context
@@ -4,19 +4,28 @@
style=,
color=,
contrastcolor=]
+
% make chapter, section bookmarks visible when opening document
\placebookmarks[chapter, section, subsection, subsubsection, subsubsubsection, subsubsubsubsection][chapter, section]
\setupinteractionscreen[option=bookmark]
\setuptagging[state=start]
+
% use microtypography
\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
\definefontfeature[smallcaps][script=latn, protrusion=quality, expansion=quality, smcp=yes, onum=yes, pnum=yes]
\setupalign[hz,hanging]
\setupitaliccorrection[global, always]
+
\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
-\usemodule[simplefonts]
-\setmainfontfallback[DejaVu Serif][range={greekandcoptic, greekextended}, force=yes, rscale=auto]
+
+\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
+\definefontfamily[mainface][rm][Latin Modern Roman]
+\definefontfamily[mainface][mm][Latin Modern Math]
+\definefontfamily[mainface][ss][Latin Modern Sans]
+\definefontfamily[mainface][tt][Latin Modern Typewriter][features=none]
+\setupbodyfont[mainface]
+
\setupwhitespace[medium]
\setuphead[chapter] [style=\tfd,header=empty]
diff --git a/test/writers-lang-and-dir.latex b/test/writers-lang-and-dir.latex
index cba3dd96b..0a7832a91 100644
--- a/test/writers-lang-and-dir.latex
+++ b/test/writers-lang-and-dir.latex
@@ -17,12 +17,31 @@
\usepackage[]{microtype}
\UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
}{}
+\IfFileExists{parskip.sty}{%
+\usepackage{parskip}
+}{% else
+\setlength{\parindent}{0pt}
+\setlength{\parskip}{6pt plus 2pt minus 1pt}
+}
\PassOptionsToPackage{hyphens}{url} % url is loaded by hyperref
\usepackage[unicode=true]{hyperref}
\hypersetup{
pdfborder={0 0 0},
breaklinks=true}
\urlstyle{same} % don't use monospace font for urls
+\setlength{\emergencystretch}{3em} % prevent overfull lines
+\providecommand{\tightlist}{%
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
+\setcounter{secnumdepth}{0}
+% 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
\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
\usepackage[shorthands=off,ngerman,british,nswissgerman,spanish,french,main=english]{babel}
\newcommand{\textgerman}[2][]{\foreignlanguage{ngerman}{#2}}
@@ -35,6 +54,7 @@
\newcommand{\textfrench}[2][]{\foreignlanguage{french}{#2}}
\newenvironment{french}[2][]{\begin{otherlanguage}{french}}{\end{otherlanguage}}
\else
+ % load polyglossia as late as possible as it *could* call bidi if RTL lang (e.g. Hebrew or Arabic)
\usepackage{polyglossia}
\setmainlanguage[]{english}
\setotherlanguage[]{german}
@@ -43,25 +63,6 @@
\setotherlanguage[]{spanish}
\setotherlanguage[]{french}
\fi
-\IfFileExists{parskip.sty}{%
-\usepackage{parskip}
-}{% else
-\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}
-% 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
\ifxetex
% load bidi as late as possible as it modifies e.g. graphicx
\usepackage{bidi}
diff --git a/trypandoc/trypandoc.hs b/trypandoc/trypandoc.hs
index 2fcfe35e7..d8652079a 100644
--- a/trypandoc/trypandoc.hs
+++ b/trypandoc/trypandoc.hs
@@ -8,6 +8,9 @@ import Network.HTTP.Types.Status (status200)
import Network.HTTP.Types.Header (hContentType)
import Network.HTTP.Types.URI (queryToQueryText)
import Text.Pandoc
+import Text.Pandoc.Highlighting (pygments)
+import Text.Pandoc.Readers (getReader, Reader(..))
+import Text.Pandoc.Writers (getWriter, Writer(..))
import Text.Pandoc.Error (PandocError)
import Text.Pandoc.Shared (tabFilter)
import Data.Aeson
@@ -25,12 +28,16 @@ app req respond = do
text <- getParam "text" >>= checkLength . fromMaybe T.empty
fromFormat <- fromMaybe "" <$> getParam "from"
toFormat <- fromMaybe "" <$> getParam "to"
- reader <- maybe (error $ "could not find reader for " ++ T.unpack fromFormat) return
- $ lookup fromFormat fromFormats
- let writer = maybe (error $ "could not find writer for " ++ T.unpack toFormat) id
- $ lookup toFormat toFormats
- let result = case reader $ tabFilter 4 $ T.unpack text of
- Right doc -> T.pack $ writer doc
+ let reader = case getReader (T.unpack fromFormat) of
+ Right (TextReader r) -> r readerOpts
+ _ -> error $ "could not find reader for "
+ ++ T.unpack fromFormat
+ let writer = case getWriter (T.unpack toFormat) of
+ Right (TextWriter w) -> w writerOpts
+ _ -> error $ "could not find writer for " ++
+ T.unpack toFormat
+ let result = case runPure $ reader (tabFilter 4 text) >>= writer of
+ Right s -> s
Left err -> error (show err)
let output = encode $ object [ T.pack "html" .= result
, T.pack "name" .=
@@ -50,52 +57,7 @@ writerOpts :: WriterOptions
writerOpts = def { writerReferenceLinks = True,
writerEmailObfuscation = NoObfuscation,
writerHTMLMathMethod = MathJax "http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML",
- writerHighlight = True }
+ writerHighlightStyle = Just pygments }
readerOpts :: ReaderOptions
-readerOpts = def { readerParseRaw = True,
- readerSmart = True }
-
-fromFormats :: [(Text, String -> Either PandocError Pandoc)]
-fromFormats = [
- ("native" , readNative)
- ,("json" , Text.Pandoc.readJSON readerOpts)
- ,("markdown" , readMarkdown readerOpts)
- ,("markdown_strict" , readMarkdown readerOpts{
- readerExtensions = strictExtensions,
- readerSmart = False })
- ,("markdown_phpextra" , readMarkdown readerOpts{
- readerExtensions = phpMarkdownExtraExtensions })
- ,("markdown_github" , readMarkdown readerOpts{
- readerExtensions = githubMarkdownExtensions })
- ,("markdown_mmd", readMarkdown readerOpts{
- readerExtensions = multimarkdownExtensions })
- ,("rst" , readRST readerOpts)
- ,("mediawiki" , readMediaWiki readerOpts)
- ,("docbook" , readDocBook readerOpts)
- ,("opml" , readOPML readerOpts)
- ,("t2t" , readTxt2TagsNoMacros readerOpts)
- ,("org" , readOrg readerOpts)
- ,("textile" , readTextile readerOpts) -- TODO : textile+lhs
- ,("html" , readHtml readerOpts)
- ,("latex" , readLaTeX readerOpts)
- ,("haddock" , readHaddock readerOpts)
- ]
-
-toFormats :: [(Text, Pandoc -> String)]
-toFormats = mapMaybe (\(x,y) ->
- case y of
- PureStringWriter w -> Just (T.pack x, w writerOpts{
- writerExtensions =
- case x of
- "markdown_strict" -> strictExtensions
- "markdown_phpextra" -> phpMarkdownExtraExtensions
- "markdown_mmd" -> multimarkdownExtensions
- "markdown_github" -> githubMarkdownExtensions
- _ -> pandocExtensions
- })
- _ ->
- case x of
- "rtf" -> Just (T.pack x, writeRTF writerOpts)
- _ -> Nothing) writers
-
+readerOpts = def