git.iko.soy/typeable/pandoc
on master help sign in
Merge branch 'master' into groff_reader
commita337685fe0ab9c63b9456f27787bbe4f0d785a94 authorYan Pashkovsky <Yanpas@users.noreply.github.com> dateWed 9 May 2018, 19:48 (8 years ago) parent8e9973b5f33d2e
416 files changed+17484−5803
.travis.yml+5−1 AUTHORS.md+6 CONTRIBUTING.md+4 COPYRIGHT+23−12 INSTALL.md+3−2 MANUAL.txt+277−191 Makefile+13−6 README.md+142−84 README.template+37−1 appveyor.yml+5−4 benchmark/benchmark-pandoc.hs+2 benchmark/weigh-pandoc.hs+2 changelog+707−2 data/LaTeXMathML.js−198 data/bash_completion.tpl+3−3 data/pptx/docProps/thumbnail.jpeg data/templates/default.context+8−1 data/templates/default.html5+1−1 data/templates/default.latex+12−6 data/templates/default.ms+4−1 data/templates/default.revealjs+5 doc/lua-filters.md+37−4 doc/org.md+95 lib/fonts/Makefile−6 lib/fonts/parseUnicodeMapping.hs−40 lib/fonts/symbol.txt−256 linux/Dockerfile+12−5 man/pandoc.1+426−154 pandoc.cabal+86−73 pandoc.hs+2 prelude/Prelude.hs+17 src/Text/Pandoc/App.hs+45−58 src/Text/Pandoc/Asciify.hs+2 src/Text/Pandoc/BCP47.hs+2 src/Text/Pandoc/CSS.hs+2 src/Text/Pandoc/CSV.hs+2 src/Text/Pandoc/Class.hs+17−6 src/Text/Pandoc/Compat/Time.hs−30 src/Text/Pandoc/Data.hs+2 src/Text/Pandoc/Emoji.hs+2 src/Text/Pandoc/Error.hs+2 src/Text/Pandoc/Extensions.hs+16−5 src/Text/Pandoc/Filter.hs+2 src/Text/Pandoc/Filter/JSON.hs+2 src/Text/Pandoc/Filter/Lua.hs+2 src/Text/Pandoc/Filter/Path.hs+2 src/Text/Pandoc/Highlighting.hs+2 src/Text/Pandoc/ImageSize.hs+7−5 src/Text/Pandoc/Logging.hs+15 src/Text/Pandoc/Lua.hs+5−2 src/Text/Pandoc/Lua/Filter.hs+2 src/Text/Pandoc/Lua/Init.hs+9−1 src/Text/Pandoc/Lua/Module/MediaBag.hs+2 src/Text/Pandoc/Lua/Module/Pandoc.hs+2 src/Text/Pandoc/Lua/Module/Utils.hs+2 src/Text/Pandoc/Lua/Packages.hs+2 src/Text/Pandoc/Lua/StackInstances.hs+2 src/Text/Pandoc/Lua/Util.hs+3−1 src/Text/Pandoc/MIME.hs+3−1 src/Text/Pandoc/MediaBag.hs+4−1 src/Text/Pandoc/Options.hs+2−3 src/Text/Pandoc/PDF.hs+26−11 src/Text/Pandoc/Parsing.hs+13−10 src/Text/Pandoc/Pretty.hs+3−2 src/Text/Pandoc/Process.hs+2 src/Text/Pandoc/Readers.hs+7−2 src/Text/Pandoc/Readers/CommonMark.hs+2 src/Text/Pandoc/Readers/Creole.hs+3−2 src/Text/Pandoc/Readers/DocBook.hs+80−12 src/Text/Pandoc/Readers/Docx.hs+70−84 src/Text/Pandoc/Readers/Docx/Combine.hs+6 src/Text/Pandoc/Readers/Docx/Fields.hs+2 src/Text/Pandoc/Readers/Docx/Lists.hs+2 src/Text/Pandoc/Readers/Docx/Parse.hs+13−14 src/Text/Pandoc/Readers/Docx/StyleMap.hs+2 src/Text/Pandoc/Readers/Docx/Util.hs+2 src/Text/Pandoc/Readers/EPUB.hs+35−7 src/Text/Pandoc/Readers/FB2.hs+404 src/Text/Pandoc/Readers/HTML.hs+7−3 src/Text/Pandoc/Readers/Haddock.hs+20−2 src/Text/Pandoc/Readers/JATS.hs+33−1 src/Text/Pandoc/Readers/LaTeX.hs+102−44 src/Text/Pandoc/Readers/LaTeX/Types.hs+2 src/Text/Pandoc/Readers/Markdown.hs+30−12 src/Text/Pandoc/Readers/MediaWiki.hs+21−9 src/Text/Pandoc/Readers/Muse.hs+317−275 src/Text/Pandoc/Readers/Native.hs+2 src/Text/Pandoc/Readers/OPML.hs+32−1 src/Text/Pandoc/Readers/Odt.hs+2 src/Text/Pandoc/Readers/Odt/Arrows/State.hs+3−5 src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs+6−4 src/Text/Pandoc/Readers/Odt/Base.hs−2 src/Text/Pandoc/Readers/Odt/ContentReader.hs+5−3 src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs+4−4 src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs+2 src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs+2 src/Text/Pandoc/Readers/Odt/Generic/Utils.hs+2 src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs+2 src/Text/Pandoc/Readers/Odt/Namespaces.hs+2 src/Text/Pandoc/Readers/Odt/StyleReader.hs+8−6 src/Text/Pandoc/Readers/Org.hs+2 src/Text/Pandoc/Readers/Org/BlockStarts.hs+2 src/Text/Pandoc/Readers/Org/Blocks.hs+2−1 src/Text/Pandoc/Readers/Org/DocumentTree.hs+2−1 src/Text/Pandoc/Readers/Org/ExportSettings.hs+2 src/Text/Pandoc/Readers/Org/Inlines.hs+2−3 src/Text/Pandoc/Readers/Org/Meta.hs+5−6 src/Text/Pandoc/Readers/Org/ParserState.hs+2 src/Text/Pandoc/Readers/Org/Parsing.hs+2 src/Text/Pandoc/Readers/Org/Shared.hs+2 src/Text/Pandoc/Readers/RST.hs+18−8 src/Text/Pandoc/Readers/TWiki.hs+5−4 src/Text/Pandoc/Readers/Textile.hs+3−2 src/Text/Pandoc/Readers/TikiWiki.hs+6−6 src/Text/Pandoc/Readers/Txt2Tags.hs+4−3 src/Text/Pandoc/Readers/Vimwiki.hs+3−1 src/Text/Pandoc/SelfContained.hs+2−1 src/Text/Pandoc/Shared.hs+20−10 src/Text/Pandoc/Slides.hs+2 src/Text/Pandoc/Templates.hs+2−4 src/Text/Pandoc/Translations.hs+4−1 src/Text/Pandoc/UTF8.hs+1 src/Text/Pandoc/UUID.hs+2 src/Text/Pandoc/Writers.hs+2 src/Text/Pandoc/Writers/AsciiDoc.hs+2 src/Text/Pandoc/Writers/CommonMark.hs+4−2 src/Text/Pandoc/Writers/ConTeXt.hs+2 src/Text/Pandoc/Writers/Custom.hs+4−1 src/Text/Pandoc/Writers/Docbook.hs+2 src/Text/Pandoc/Writers/Docx.hs+113−92 src/Text/Pandoc/Writers/DokuWiki.hs+18−8 src/Text/Pandoc/Writers/EPUB.hs+22−13 src/Text/Pandoc/Writers/FB2.hs+16−33 src/Text/Pandoc/Writers/HTML.hs+31−43 src/Text/Pandoc/Writers/Haddock.hs+7−60 src/Text/Pandoc/Writers/ICML.hs+4−2 src/Text/Pandoc/Writers/JATS.hs+8−6 src/Text/Pandoc/Writers/LaTeX.hs+12−9 src/Text/Pandoc/Writers/Man.hs+2 src/Text/Pandoc/Writers/Markdown.hs+6−1 src/Text/Pandoc/Writers/Math.hs+2 src/Text/Pandoc/Writers/MediaWiki.hs+2 src/Text/Pandoc/Writers/Ms.hs+37−11 src/Text/Pandoc/Writers/Muse.hs+238−100 src/Text/Pandoc/Writers/Native.hs+2 src/Text/Pandoc/Writers/ODT.hs+2 src/Text/Pandoc/Writers/OOXML.hs+2−1 src/Text/Pandoc/Writers/OPML.hs+4−7 src/Text/Pandoc/Writers/OpenDocument.hs+2 src/Text/Pandoc/Writers/Org.hs+4−2 src/Text/Pandoc/Writers/Powerpoint.hs+2 src/Text/Pandoc/Writers/Powerpoint/Output.hs+95−92 src/Text/Pandoc/Writers/Powerpoint/Presentation.hs+132−97 src/Text/Pandoc/Writers/RST.hs+119−24 src/Text/Pandoc/Writers/RTF.hs+2 src/Text/Pandoc/Writers/Shared.hs+33−12 src/Text/Pandoc/Writers/TEI.hs+2 src/Text/Pandoc/Writers/Texinfo.hs+2 src/Text/Pandoc/Writers/Textile.hs+2 src/Text/Pandoc/Writers/ZimWiki.hs+2 src/Text/Pandoc/XML.hs+2 stack.lts9.yaml+14−14 stack.yaml+12−10 test/Tests/Command.hs+2 test/Tests/Command.hs.orig+95 test/Tests/Helpers.hs+2 test/Tests/Helpers.hs.orig+138 test/Tests/Lua.hs+16−1 test/Tests/Lua.hs.orig+196 test/Tests/Old.hs+4−2 test/Tests/Old.hs.orig+288 test/Tests/Readers/Creole.hs+2 test/Tests/Readers/Creole.hs.orig+286 test/Tests/Readers/Docx.hs+14 test/Tests/Readers/Docx.hs.orig+405 test/Tests/Readers/EPUB.hs+2 test/Tests/Readers/EPUB.hs.orig+40 test/Tests/Readers/FB2.hs+29 test/Tests/Readers/HTML.hs+2 test/Tests/Readers/HTML.hs.orig+54 test/Tests/Readers/JATS.hs+2 test/Tests/Readers/JATS.hs.orig+116 test/Tests/Readers/LaTeX.hs+2 test/Tests/Readers/LaTeX.hs.orig+341 test/Tests/Readers/Markdown.hs+5 test/Tests/Readers/Markdown.hs.orig+462 test/Tests/Readers/Muse.hs+168−22 test/Tests/Readers/Muse.hs.orig+1262 test/Tests/Readers/Odt.hs+2 test/Tests/Readers/Odt.hs.orig+170 test/Tests/Readers/Org.hs.orig+16 test/Tests/Readers/Org/Block.hs+2 test/Tests/Readers/Org/Block.hs.orig+192 test/Tests/Readers/Org/Block/CodeBlock.hs+2 test/Tests/Readers/Org/Block/CodeBlock.hs.orig+194 test/Tests/Readers/Org/Block/Figure.hs+2 test/Tests/Readers/Org/Block/Figure.hs.orig+57 test/Tests/Readers/Org/Block/Header.hs+2 test/Tests/Readers/Org/Block/Header.hs.orig+182 test/Tests/Readers/Org/Block/List.hs+2 test/Tests/Readers/Org/Block/List.hs.orig+244 test/Tests/Readers/Org/Block/Table.hs+2 test/Tests/Readers/Org/Block/Table.hs.orig+150 test/Tests/Readers/Org/Directive.hs+2 test/Tests/Readers/Org/Directive.hs.orig+199 test/Tests/Readers/Org/Inline.hs+4−167 test/Tests/Readers/Org/Inline.hs.orig+352 test/Tests/Readers/Org/Inline/Citation.hs+181 test/Tests/Readers/Org/Inline/Citation.hs.orig+179 test/Tests/Readers/Org/Inline/Note.hs+2 test/Tests/Readers/Org/Inline/Note.hs.orig+86 test/Tests/Readers/Org/Inline/Smart.hs+2 test/Tests/Readers/Org/Inline/Smart.hs.orig+46 test/Tests/Readers/Org/Meta.hs+2 test/Tests/Readers/Org/Meta.hs.orig+191 test/Tests/Readers/Org/Shared.hs+2 test/Tests/Readers/Org/Shared.hs.orig+29 test/Tests/Readers/RST.hs+3−1 test/Tests/Readers/RST.hs.orig+189 test/Tests/Readers/Txt2Tags.hs+3−1 test/Tests/Readers/Txt2Tags.hs.orig+437 test/Tests/Shared.hs+2 test/Tests/Shared.hs.orig+39 test/Tests/Writers/AsciiDoc.hs+2 test/Tests/Writers/AsciiDoc.hs.orig+56 test/Tests/Writers/ConTeXt.hs+2 test/Tests/Writers/ConTeXt.hs.orig+149 test/Tests/Writers/Docbook.hs+2 test/Tests/Writers/Docbook.hs.orig+303 test/Tests/Writers/Docx.hs+2 test/Tests/Writers/Docx.hs.orig+157 test/Tests/Writers/FB2.hs+4−2 test/Tests/Writers/FB2.hs.orig+34 test/Tests/Writers/HTML.hs+2 test/Tests/Writers/HTML.hs.orig+44 test/Tests/Writers/JATS.hs+14−26 test/Tests/Writers/JATS.hs.orig+108 test/Tests/Writers/LaTeX.hs+2 test/Tests/Writers/LaTeX.hs.orig+176 test/Tests/Writers/Markdown.hs+2 test/Tests/Writers/Markdown.hs.orig+267 test/Tests/Writers/Muse.hs+117−26 test/Tests/Writers/Muse.hs.orig+410 test/Tests/Writers/Native.hs+2 test/Tests/Writers/Native.hs.orig+22 test/Tests/Writers/OOXML.hs+2−2 test/Tests/Writers/OOXML.hs.orig+184 test/Tests/Writers/Org.hs+2 test/Tests/Writers/Org.hs.orig+25 test/Tests/Writers/Plain.hs+2 test/Tests/Writers/Plain.hs.orig+21 test/Tests/Writers/Powerpoint.hs+19 test/Tests/Writers/Powerpoint.hs.orig+93 test/Tests/Writers/RST.hs+51−9 test/Tests/Writers/RST.hs.orig+130 test/Tests/Writers/TEI.hs+2 test/Tests/Writers/TEI.hs.orig+43 test/command/1710.md+2−3 test/command/2649.md+11−9 test/command/3348.md+1−1 test/command/3510-src.hs.orig+1 test/command/3587.md+36 test/command/3675.md+2−2 test/command/4016.md+2−3 test/command/4320.md+15 test/command/4424.md+10 test/command/4454.md+9 test/command/4513.md+9 test/command/4527.md+21 test/command/4529.md+36 test/command/4550.md+7 test/command/4576.md+6 test/command/4578.md+14 test/command/4579.md+16 test/command/4589.md+14 test/command/4594.md+24 test/command/4598.md+10 test/command/sloppypar.md+23 test/docx/adjacent_codeblocks.docx test/docx/adjacent_codeblocks.native+6 test/docx/block_quotes.docx test/docx/char_styles.docx test/docx/custom-style-with-styles.native+1−1 test/docx/deep_normalize.docx test/docx/drop_cap.docx test/docx/golden/image.docx test/docx/golden/inline_formatting.docx test/docx/golden/inline_images.docx test/docx/hanging_indent.docx test/docx/headers.docx test/docx/image_writer_test.native+8−5 test/docx/inline_formatting.docx test/docx/inline_images.docx test/docx/link_in_notes.docx test/docx/links.docx test/docx/lists.docx test/docx/metadata.docx test/docx/metadata_after_normal.docx test/docx/nested_sdt.docx test/docx/nested_sdt.native+3 test/docx/nested_smart_tags.docx test/docx/nested_smart_tags.native+7 test/docx/normalize.docx test/docx/notes.docx test/docx/numbered_header.docx test/docx/table_variable_width.native+3 test/docx/table_with_list_cell.docx test/docx/tables.docx test/dokuwiki_multiblock_table.dokuwiki+4−3 test/dokuwiki_multiblock_table.native+6−1 test/fb2/basic.fb2+74−2 test/fb2/meta.fb2+3 test/fb2/meta.markdown+7 test/fb2/reader/emphasis.fb2+11 test/fb2/reader/emphasis.native+6 test/fb2/reader/epigraph.fb2+18 test/fb2/reader/epigraph.native+9 test/fb2/reader/meta.fb2+26 test/fb2/reader/meta.native+2 test/fb2/reader/poem.fb2+28 test/fb2/reader/poem.native+14 test/fb2/reader/titles.fb2+18 test/fb2/reader/titles.native+8 test/fb2/titles.fb2+1−1 test/fb2/titles.markdown+1−1 test/jats-reader.native+2−2 test/jats-reader.xml+352−977 test/lhs-test.rst+5−5 test/lhs-test.rst+lhs+2−2 test/lua/math.lua+10 test/lua/script-name.lua+3 test/lua/test-pandoc-utils.lua+21−13 test/pandoc-test14632-86+1448 test/pandoc-test14632-89 test/pandoc-test14632-90 test/pandoc-test14632-91 test/pandoc-test14632-94 test/pandoc-test14632-95 test/pandoc-test14632-96 test/pandoc-test14632-97 test/pandoc-test77993-78 test/pandoc-test77993-79 test/pandoc-test77993-82 test/pandoc-test77993-83 test/pandoc-test77993-86 test/pandoc-test77993-87 test/pandoc-test77993-90 test/pandoc-test77993-91 test/pandoc-test88473-110 test/pandoc-test88473-111 test/pandoc-test88473-112 test/pandoc-test88473-113 test/pandoc-test88473-116 test/pandoc-test88473-117 test/pandoc-test88473-118 test/pandoc-test88473-119 test/pandoc-test94017-86 test/pandoc-test94017-87 test/pandoc-test94017-90 test/pandoc-test94017-91 test/pandoc-test94017-92 test/pandoc-test94017-93 test/pptx/endnotes_templated.pptx test/pptx/endnotes_toc_templated.pptx test/pptx/images_templated.pptx test/pptx/lists.native+18 test/pptx/lists.pptx test/pptx/lists_templated.pptx test/pptx/remove_empty_slides.native+5 test/pptx/remove_empty_slides.pptx test/pptx/remove_empty_slides_templated.pptx test/pptx/slide_breaks_slide_level_1_templated.pptx test/pptx/slide_breaks_templated.pptx test/pptx/slide_breaks_toc_templated.pptx test/pptx/speaker_notes_afterseps.native+33 test/pptx/speaker_notes_afterseps.pptx test/pptx/speaker_notes_afterseps_templated.pptx test/pptx/tables.native+35 test/pptx/tables.pptx test/pptx/tables_templated.pptx test/s5-fancy.html+2−202 test/tables-rstsubset.native+6−6 test/tables.asciidoc+3−3 test/tables.context+8−8 test/tables.custom+3−3 test/tables.docbook4+3−3 test/tables.docbook5+3−3 test/tables.fb2+14−1 test/tables.haddock+67−53 test/tables.html4+6−6 test/tables.html5+6−6 test/tables.icml+3−3 test/tables.jats+105−309 test/tables.latex+9−9 test/tables.man+3−3 test/tables.markdown+8−8 test/tables.mediawiki+3−3 test/tables.ms+7−7 test/tables.native+3−3 test/tables.plain+8−8 test/tables.rst+30−30 test/tables.rtf+8−8 test/tables.texinfo+3−3 test/tables.textile+3−3 test/test-pandoc.hs+4 test/test-pandoc.hs.orig+83 test/writer.context+1−1 test/writer.fb2+114−362 test/writer.jats+357−923 test/writer.ms+54−51 test/writer.muse+13−13 test/writer.rst+67−67 test/writers-lang-and-dir.context+1−1 test/writers-lang-and-dir.latex+2−2 tools/update-readme.lua+16−32 trypandoc/trypandoc.hs+2
.travis.yml+5−1
@@ -49,6 +49,10 @@ matrix:
4949 compiler: ": #GHC 8.2.2"
5050 addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2,happy-1.19.5], sources: [hvr-ghc]}}
5151
52+ - env: BUILD=cabal GHCVER=8.4.1 CABALVER=2.0 OPTS="-O0 -Wall -Wincomplete-record-updates -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -fno-warn-unused-do-bind -Werror" FLAGS="fast embed_data_files" CABALARGS="--enable-benchmarks"
53+ compiler: ": #GHC 8.4.1"
54+ addons: {apt: {packages: [cabal-install-2.0,ghc-8.4.1,happy-1.19.5], sources: [hvr-ghc]}}
55+
5256 # Build with the newest GHC and cabal-install. This is an accepted failure,
5357 # see below.
5458 # - env: BUILD=cabal GHCVER=head CABALVER=head CABALAGS="--allow-newer"
@@ -123,7 +127,7 @@ script:
123127 stack)
124128 ulimit -n 4096
125129 stack config set system-ghc --global true
126− stack --no-terminal $ARGS test --fast --flag 'aeson:fast' --flag pandoc:embed_data_files --haddock --no-haddock-deps --ghc-options="$OPTS"
130+ stack --no-terminal $ARGS test --fast --flag 'aeson:fast' --flag pandoc:embed_data_files --haddock --no-haddock-deps --ghc-options="$OPTS" --test-arguments='--hide-successes'
127131 ;;
128132 cabal)
129133 cabal sdist --output-directory=sourcedist && \
AUTHORS.md+6
@@ -1,5 +1,6 @@
11# Contributors
22
3+- Anabra
34- Arata Mizuki
45- Aaron Wolen
56- Albert Krewinkel
@@ -49,8 +50,10 @@
4950- Emily Eisenberg
5051- Eric Kow
5152- Eric Seidel
53+- Étienne Bersac
5254- Felix Yan
5355- Florian Eitel
56+- Francesco Occhipinti
5457- François Gannaz
5558- Freiric Barral
5659- Freirich Raabe
@@ -83,6 +86,7 @@
8386- Jens Getreu
8487- Jens Petersen
8588- Jesse Rosenthal
89+- Joe Hermaszewski
8690- Joe Hillenbrand
8791- John MacFarlane
8892- John Muccigrosso
@@ -129,6 +133,7 @@
129133- Nick Bart
130134- Nicolas Kaiser
131135- Nikolay Yakimov
136+- Nokome Bentley
132137- Oliver Matthews
133138- Ophir Lifshitz
134139- Or Neeman
@@ -186,6 +191,7 @@
186191- lwolfsonkin
187192- nkalvi
188193- oltolm
194+- quasicomputational
189195- qerub
190196- robabla
191197- roblabla
CONTRIBUTING.md+4
@@ -205,6 +205,10 @@ placed in the source directory):
205205Profiling
206206---------
207207
208+To diagnose a performance issue with parsing, first try using
209+the `--trace` option. This will give you a record of when block
210+parsers succeed, so you can spot backtracking issues.
211+
208212To use the GHC profiler with cabal:
209213
210214 cabal clean
COPYRIGHT+23−12
@@ -69,8 +69,9 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
6969OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
7070
7171----------------------------------------------------------------------
72−Pandoc's templates (in `data/templates`) are dual-licensed GPL (v2 or
73−higher, same as pandoc) and the BSD 3-clause license.
72+Pandoc's templates (in `data/templates`) are dual-licensed as either
73+GPL (v2 or higher, same as pandoc) or (at your option) the BSD
74+3-clause license.
7475
7576Copyright (c) 2014--2018, John MacFarlane
7677
@@ -118,6 +119,24 @@ Copyright (C) 2010-2018 Paul Rivier and John MacFarlane
118119
119120Released under the GNU General Public License version 2 or later.
120121
122+----------------------------------------------------------------------
123+src/Text/Pandoc/Readers/TikiWiki.hs
124+Copyright (C) 2017 Robin Lee Powell
125+
126+Released under the GNU General Public License version 2 or later.
127+
128+----------------------------------------------------------------------
129+src/Text/Pandoc/Readers/JATS.hs
130+Copyright (C) 2017-2018 Hamish Mackenzie
131+
132+Released under the GNU General Public License version 2 or later.
133+
134+----------------------------------------------------------------------
135+src/Text/Pandoc/Readers/EPUB.hs
136+Copyright (C) 2014-2018 Matthew Pickering
137+
138+Released under the GNU General Public License version 2 or later.
139+
121140----------------------------------------------------------------------
122141src/Text/Pandoc/Readers/Org.hs
123142src/Text/Pandoc/Readers/Org/*
@@ -127,20 +146,12 @@ Copyright (C) 2014-2018 Albert Krewinkel
127146Released under the GNU General Public License version 2 or later.
128147
129148----------------------------------------------------------------------
130−data/LaTeXMathML.js
131−Adapted by Jeff Knisely and Douglas Woodall from
132−ASCIIMathML.js v. 1.4.7
133−Copyright (C) 2005 Peter Jipsen
149+src/Text/Pandoc/Readers/FB2.hs
150+Copyright (C) 2018 Alexander Krotov
134151
135152Released under the GNU General Public License version 2 or later.
136153
137154----------------------------------------------------------------------
138−data/MathMLinHTML.js
139−Copyright (C) 2004 Peter Jipsen http://www.chapman.edu/~jipsen
140−
141−Released under the GNU General Public License version 2 or later.
142−
143−------------------------------------------------------------------------
144155data/pandoc.lua
145156Copyright (C) 2017-2018 Albert Krewinkel
146157
INSTALL.md+3−2
@@ -125,7 +125,7 @@ The easiest way to build pandoc from source is to use [stack]:
1251252. Change to the pandoc source directory and issue the following commands:
126126
127127 stack setup
128− stack install --test
128+ stack install
129129
130130 `stack setup` will automatically download the ghc compiler
131131 if you don't have it. `stack install` will install the
@@ -145,7 +145,7 @@ The easiest way to build pandoc from source is to use [stack]:
145145
1461463. Use `cabal` to install pandoc and its dependencies:
147147
148− cabal install pandoc --enable-tests
148+ cabal install pandoc
149149
150150 This procedure will install the released version of pandoc,
151151 which will be downloaded automatically from HackageDB.
@@ -272,6 +272,7 @@ test`.
272272To run particular tests (pattern-matching on their names), use
273273the `-p` option:
274274
275+ cabal install pandoc --enable-tests
275276 cabal test --test-options='-p markdown'
276277
277278Or with stack:
MANUAL.txt+277−191
@@ -1,6 +1,6 @@
11% Pandoc User's Guide
22% John MacFarlane
3−% January 18, 2018
3+% April 26, 2018
44
55Synopsis
66========
@@ -13,37 +13,19 @@ Description
1313Pandoc is a [Haskell] library for converting from one markup format to
1414another, and a command-line tool that uses this library.
1515
16−Pandoc can read [Markdown], [CommonMark], [PHP Markdown Extra],
17−[GitHub-Flavored Markdown], [MultiMarkdown], and (subsets of) [Textile],
18−[reStructuredText], [HTML], [LaTeX], [MediaWiki markup], [TWiki
19−markup], [TikiWiki markup], [Creole 1.0], [Haddock markup], [OPML],
20−[Emacs Org mode], [DocBook], [JATS], [Muse], [txt2tags], [Vimwiki],
21−[EPUB], [ODT], and [Word docx].
22−
23−Pandoc can write plain text, [Markdown],
24−[CommonMark], [PHP Markdown Extra], [GitHub-Flavored Markdown],
25−[MultiMarkdown], [reStructuredText], [XHTML], [HTML5], [LaTeX]
26−\(including [`beamer`] slide shows\), [ConTeXt], [RTF], [OPML],
27−[DocBook], [JATS], [OpenDocument], [ODT], [Word docx], [GNU Texinfo],
28−[MediaWiki markup], [DokuWiki markup], [ZimWiki markup], [Haddock
29−markup], [EPUB] \(v2 or v3\), [FictionBook2], [Textile], [groff man],
30−[groff ms], [Emacs Org mode], [AsciiDoc], [InDesign ICML], [TEI
31−Simple], [Muse], [PowerPoint] slide shows and [Slidy], [Slideous],
32−[DZSlides], [reveal.js] or [S5] HTML slide shows. It can also produce
33−[PDF] output on systems where LaTeX, ConTeXt, `pdfroff`,
34−`wkhtmltopdf`, `prince`, or `weasyprint` is installed.
16+Pandoc can convert between numerous markup and word processing formats,
17+including, but not limited to, various flavors of [Markdown], [HTML],
18+[LaTeX] and [Word docx]. For the full lists of input and output formats,
19+see the `--from` and `--to` [options below][General options].
20+Pandoc can also produce [PDF] output: see [creating a PDF], below.
3521
3622Pandoc's enhanced version of Markdown includes syntax for [tables],
37−[definition lists], [metadata blocks], [`Div` blocks][Extension:
38−`fenced_divs`], [footnotes] and [citations], embedded
39−[LaTeX][Extension: `raw_tex`] (including [math]), [Markdown inside HTML
40−block elements][Extension: `markdown_in_html_blocks`], and much more.
41−These enhancements, described further under [Pandoc's Markdown],
42−can be disabled using the `markdown_strict` format.
23+[definition lists], [metadata blocks], [footnotes], [citations], [math],
24+and much more. See below under [Pandoc's Markdown].
4325
4426Pandoc has a modular design: it consists of a set of readers, which parse
4527text in a given format and produce a native representation of the document
46−(like an _abstract syntax tree_ or AST), and a set of writers, which convert
28+(an _abstract syntax tree_ or AST), and a set of writers, which convert
4729this native representation into a target format. Thus, adding an input
4830or output format requires only adding a reader or writer. Users can also
4931run custom [pandoc filters] to modify the intermediate AST.
@@ -58,56 +40,6 @@ model. While conversions from pandoc's Markdown to all formats aspire
5840to be perfect, conversions from formats more expressive than pandoc's
5941Markdown can be expected to be lossy.
6042
61−[Markdown]: http://daringfireball.net/projects/markdown/
62−[CommonMark]: http://commonmark.org
63−[PHP Markdown Extra]: https://michelf.ca/projects/php-markdown/extra/
64−[GitHub-Flavored Markdown]: https://help.github.com/articles/github-flavored-markdown/
65−[MultiMarkdown]: http://fletcherpenney.net/multimarkdown/
66−[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
67−[S5]: http://meyerweb.com/eric/tools/s5/
68−[Slidy]: http://www.w3.org/Talks/Tools/Slidy/
69−[Slideous]: http://goessner.net/articles/slideous/
70−[HTML]: http://www.w3.org/html/
71−[HTML5]: http://www.w3.org/TR/html5/
72−[polyglot markup]: https://www.w3.org/TR/html-polyglot/
73−[XHTML]: http://www.w3.org/TR/xhtml1/
74−[LaTeX]: http://latex-project.org
75−[`beamer`]: https://ctan.org/pkg/beamer
76−[Beamer User's Guide]: http://ctan.math.utah.edu/ctan/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf
77−[ConTeXt]: http://www.contextgarden.net/
78−[RTF]: http://en.wikipedia.org/wiki/Rich_Text_Format
79−[DocBook]: http://docbook.org
80−[JATS]: https://jats.nlm.nih.gov
81−[txt2tags]: http://txt2tags.org
82−[EPUB]: http://idpf.org/epub
83−[OPML]: http://dev.opml.org/spec2.html
84−[OpenDocument]: http://opendocument.xml.org
85−[ODT]: http://en.wikipedia.org/wiki/OpenDocument
86−[Textile]: http://redcloth.org/textile
87−[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting
88−[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
89−[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html
90−[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules
91−[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax
92−[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html
93−[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0
94−[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html
95−[groff ms]: http://man7.org/linux/man-pages/man7/groff_ms.7.html
96−[Haskell]: https://www.haskell.org
97−[GNU Texinfo]: http://www.gnu.org/software/texinfo/
98−[Emacs Org mode]: http://orgmode.org
99−[AsciiDoc]: http://www.methods.co.nz/asciidoc/
100−[DZSlides]: http://paulrouget.com/dzslides/
101−[Word docx]: https://en.wikipedia.org/wiki/Office_Open_XML
102−[PDF]: https://www.adobe.com/pdf/
103−[reveal.js]: http://lab.hakim.se/reveal-js/
104−[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
105−[InDesign ICML]: http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf
106−[TEI Simple]: https://github.com/TEIC/TEI-Simple
107−[Muse]: https://amusewiki.org/library/manual
108−[PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint
109−[Vimwiki]: https://vimwiki.github.io
110−
11143Using `pandoc`
11244--------------
11345
@@ -283,20 +215,42 @@ General options
283215
284216`-f` *FORMAT*, `-r` *FORMAT*, `--from=`*FORMAT*, `--read=`*FORMAT*
285217
286−: Specify input format. *FORMAT* can be `native` (native Haskell),
287− `json` (JSON version of native AST), `markdown` (pandoc's
288− extended Markdown), `markdown_strict` (original unextended
289− Markdown), `markdown_phpextra` (PHP Markdown Extra),
290− `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored Markdown),
291− `commonmark` (CommonMark Markdown), `textile` (Textile), `rst`
292− (reStructuredText), `html` (HTML), `docbook` (DocBook), `t2t`
293− (txt2tags), `docx` (docx), `odt` (ODT), `epub` (EPUB), `opml` (OPML),
294− `org` (Emacs Org mode), `mediawiki` (MediaWiki markup), `twiki` (TWiki
295− markup), `tikiwiki` (TikiWiki markup), `creole` (Creole 1.0),
296− `haddock` (Haddock markup), or `latex` (LaTeX).
297− (`markdown_github` provides deprecated and less accurate support
298− for Github-Flavored Markdown; please use `gfm` instead, unless you
299− need to use extensions other than `smart`.)
218+: Specify input format. *FORMAT* can be:
219+
220+ ::: {#input-formats}
221+ - `commonmark` ([CommonMark] Markdown)
222+ - `creole` ([Creole 1.0])
223+ - `docbook` ([DocBook])
224+ - `docx` ([Word docx])
225+ - `epub` ([EPUB])
226+ - `fb2` ([FictionBook2] e-book)
227+ - `gfm` ([GitHub-Flavored Markdown]),
228+ or `markdown_github`, which provides deprecated and less accurate
229+ support for Github-Flavored Markdown; please use `gfm` instead,
230+ unless you need to use extensions other than `smart`.
231+ - `haddock` ([Haddock markup])
232+ - `html` ([HTML])
233+ - `jats` ([JATS] XML)
234+ - `json` (JSON version of native AST)
235+ - `latex` ([LaTeX])
236+ - `markdown` ([Pandoc's Markdown])
237+ - `markdown_mmd` ([MultiMarkdown])
238+ - `markdown_phpextra` ([PHP Markdown Extra])
239+ - `markdown_strict` (original unextended [Markdown])
240+ - `mediawiki` ([MediaWiki markup])
241+ - `muse` ([Muse])
242+ - `native` (native Haskell)
243+ - `odt` ([ODT])
244+ - `opml` ([OPML])
245+ - `org` ([Emacs Org mode])
246+ - `rst` ([reStructuredText])
247+ - `t2t` ([txt2tags])
248+ - `textile` ([Textile])
249+ - `tikiwiki` ([TikiWiki markup])
250+ - `twiki` ([TWiki markup])
251+ - `vimwiki` ([Vimwiki])
252+ :::
253+
300254 Extensions can be individually enabled or disabled by
301255 appending `+EXTENSION` or `-EXTENSION` to the format name.
302256 See [Extensions] below, for a list of extensions and
@@ -305,34 +259,64 @@ General options
305259
306260`-t` *FORMAT*, `-w` *FORMAT*, `--to=`*FORMAT*, `--write=`*FORMAT*
307261
308−: Specify output format. *FORMAT* can be `native` (native Haskell),
309− `json` (JSON version of native AST), `plain` (plain text),
310− `markdown` (pandoc's extended Markdown), `markdown_strict`
311− (original unextended Markdown), `markdown_phpextra` (PHP Markdown
312− Extra), `markdown_mmd` (MultiMarkdown), `gfm` (GitHub-Flavored
313− Markdown), `commonmark` (CommonMark Markdown), `rst`
314− (reStructuredText), `html4` (XHTML 1.0 Transitional), `html` or
315− `html5` (HTML5/XHTML [polyglot markup]), `latex` (LaTeX), `beamer`
316− (LaTeX beamer slide show), `context` (ConTeXt), `man` (groff man),
317− `mediawiki` (MediaWiki markup), `dokuwiki` (DokuWiki markup),
318− `zimwiki` (ZimWiki markup), `textile` (Textile), `org` (Emacs Org
319− mode), `texinfo` (GNU Texinfo), `opml` (OPML), `docbook` or
320− `docbook4` (DocBook 4), `docbook5` (DocBook 5), `jats` (JATS XML),
321− `opendocument` (OpenDocument), `odt` (OpenOffice text document),
322− `docx` (Word docx), `haddock` (Haddock markup), `rtf` (rich text
323− format), `epub2` (EPUB v2 book), `epub` or `epub3` (EPUB v3),
324− `fb2` (FictionBook2 e-book), `asciidoc` (AsciiDoc), `icml`
325− (InDesign ICML), `tei` (TEI Simple), `slidy` (Slidy HTML and
326− JavaScript slide show), `slideous` (Slideous HTML and JavaScript
327− slide show), `dzslides` (DZSlides HTML5 + JavaScript slide show),
328− `revealjs` (reveal.js HTML5 + JavaScript slide show), `s5` (S5
329− HTML and JavaScript slide show), `pptx` (PowerPoint slide show) or
330− the path of a custom lua writer (see [Custom writers],
331− below). (`markdown_github` provides deprecated and less accurate
332− support for Github-Flavored Markdown; please use `gfm` instead,
333− unless you use extensions that do not work with `gfm`.) Note that
334− `odt`, `docx`, and `epub` output will not be directed to *stdout*
335− unless forced with `-o -`. Extensions can be individually enabled or
262+: Specify output format. *FORMAT* can be:
263+
264+ ::: {#output-formats}
265+ - `asciidoc` ([AsciiDoc])
266+ - `beamer` ([LaTeX beamer][`beamer`] slide show)
267+ - `commonmark` ([CommonMark] Markdown)
268+ - `context` ([ConTeXt])
269+ - `docbook` or `docbook4` ([DocBook] 4)
270+ - `docbook5` (DocBook 5)
271+ - `docx` ([Word docx])
272+ - `dokuwiki` ([DokuWiki markup])
273+ - `epub` or `epub3` ([EPUB] v3 book)
274+ - `epub2` (EPUB v2)
275+ - `fb2` ([FictionBook2] e-book)
276+ - `gfm` ([GitHub-Flavored Markdown]),
277+ or `markdown_github`, which provides deprecated and less accurate
278+ support for Github-Flavored Markdown; please use `gfm` instead,
279+ unless you use extensions that do not work with `gfm`.
280+ - `haddock` ([Haddock markup])
281+ - `html` or `html5` ([HTML], i.e. [HTML5]/XHTML [polyglot markup])
282+ - `html4` ([XHTML] 1.0 Transitional)
283+ - `icml` ([InDesign ICML])
284+ - `jats` ([JATS] XML)
285+ - `json` (JSON version of native AST)
286+ - `latex` ([LaTeX])
287+ - `man` ([groff man])
288+ - `markdown` ([Pandoc's Markdown])
289+ - `markdown_mmd` ([MultiMarkdown])
290+ - `markdown_phpextra` ([PHP Markdown Extra])
291+ - `markdown_strict` (original unextended [Markdown])
292+ - `mediawiki` ([MediaWiki markup])
293+ - `ms` ([groff ms])
294+ - `muse` ([Muse]),
295+ - `native` (native Haskell),
296+ - `odt` ([OpenOffice text document][ODT])
297+ - `opml` ([OPML])
298+ - `opendocument` ([OpenDocument])
299+ - `org` ([Emacs Org mode])
300+ - `plain` (plain text),
301+ - `pptx` ([PowerPoint] slide show)
302+ - `rst` ([reStructuredText])
303+ - `rtf` ([Rich Text Format])
304+ - `texinfo` ([GNU Texinfo])
305+ - `textile` ([Textile])
306+ - `slideous` ([Slideous] HTML and JavaScript slide show)
307+ - `slidy` ([Slidy] HTML and JavaScript slide show)
308+ - `dzslides` ([DZSlides] HTML5 + JavaScript slide show),
309+ - `revealjs` ([reveal.js] HTML5 + JavaScript slide show)
310+ - `s5` ([S5] HTML and JavaScript slide show)
311+ - `tei` ([TEI Simple])
312+ - `zimwiki` ([ZimWiki markup])
313+ - the path of a custom lua writer, see [Custom writers] below
314+ :::
315+
316+ Note that `odt`, `docx`, and `epub` output will not be directed
317+ to *stdout* unless forced with `-o -`.
318+
319+ Extensions can be individually enabled or
336320 disabled by appending `+EXTENSION` or `-EXTENSION` to the format
337321 name. See [Extensions] below, for a list of extensions and their
338322 names. See `--list-output-formats` and `--list-extensions`, below.
@@ -424,6 +408,56 @@ General options
424408
425409: Show usage message.
426410
411+[Markdown]: http://daringfireball.net/projects/markdown/
412+[CommonMark]: http://commonmark.org
413+[PHP Markdown Extra]: https://michelf.ca/projects/php-markdown/extra/
414+[GitHub-Flavored Markdown]: https://help.github.com/articles/github-flavored-markdown/
415+[MultiMarkdown]: http://fletcherpenney.net/multimarkdown/
416+[reStructuredText]: http://docutils.sourceforge.net/docs/ref/rst/introduction.html
417+[S5]: http://meyerweb.com/eric/tools/s5/
418+[Slidy]: http://www.w3.org/Talks/Tools/Slidy/
419+[Slideous]: http://goessner.net/articles/slideous/
420+[HTML]: http://www.w3.org/html/
421+[HTML5]: http://www.w3.org/TR/html5/
422+[polyglot markup]: https://www.w3.org/TR/html-polyglot/
423+[XHTML]: http://www.w3.org/TR/xhtml1/
424+[LaTeX]: http://latex-project.org
425+[`beamer`]: https://ctan.org/pkg/beamer
426+[Beamer User's Guide]: http://ctan.math.utah.edu/ctan/tex-archive/macros/latex/contrib/beamer/doc/beameruserguide.pdf
427+[ConTeXt]: http://www.contextgarden.net/
428+[Rich Text Format]: http://en.wikipedia.org/wiki/Rich_Text_Format
429+[DocBook]: http://docbook.org
430+[JATS]: https://jats.nlm.nih.gov
431+[txt2tags]: http://txt2tags.org
432+[EPUB]: http://idpf.org/epub
433+[OPML]: http://dev.opml.org/spec2.html
434+[OpenDocument]: http://opendocument.xml.org
435+[ODT]: http://en.wikipedia.org/wiki/OpenDocument
436+[Textile]: http://redcloth.org/textile
437+[MediaWiki markup]: https://www.mediawiki.org/wiki/Help:Formatting
438+[DokuWiki markup]: https://www.dokuwiki.org/dokuwiki
439+[ZimWiki markup]: http://zim-wiki.org/manual/Help/Wiki_Syntax.html
440+[TWiki markup]: http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules
441+[TikiWiki markup]: https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax
442+[Haddock markup]: https://www.haskell.org/haddock/doc/html/ch03s08.html
443+[Creole 1.0]: http://www.wikicreole.org/wiki/Creole1.0
444+[groff man]: http://man7.org/linux/man-pages/man7/groff_man.7.html
445+[groff ms]: http://man7.org/linux/man-pages/man7/groff_ms.7.html
446+[Haskell]: https://www.haskell.org
447+[GNU Texinfo]: http://www.gnu.org/software/texinfo/
448+[Emacs Org mode]: http://orgmode.org
449+[AsciiDoc]: http://www.methods.co.nz/asciidoc/
450+[DZSlides]: http://paulrouget.com/dzslides/
451+[Word docx]: https://en.wikipedia.org/wiki/Office_Open_XML
452+[PDF]: https://www.adobe.com/pdf/
453+[reveal.js]: http://lab.hakim.se/reveal-js/
454+[FictionBook2]: http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1
455+[InDesign ICML]: http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf
456+[TEI Simple]: https://github.com/TEIC/TEI-Simple
457+[Muse]: https://amusewiki.org/library/manual
458+[PowerPoint]: https://en.wikipedia.org/wiki/Microsoft_PowerPoint
459+[Vimwiki]: https://vimwiki.github.io
460+
427461Reader options
428462--------------
429463
@@ -521,17 +555,27 @@ Reader options
521555
522556 return {{Str = expand_hello_world}}
523557
558+ In order of preference, pandoc will look for lua filters in
559+
560+ 1. a specified full or relative path (executable or
561+ non-executable)
562+
563+ 2. `$DATADIR/filters` (executable or non-executable)
564+ where `$DATADIR` is the user data directory (see
565+ `--data-dir`, above).
524566
525567`-M` *KEY*[`=`*VAL*], `--metadata=`*KEY*[`:`*VAL*]
526568
527569: Set the metadata field *KEY* to the value *VAL*. A value specified
528− on the command line overrides a value specified in the document.
570+ on the command line overrides a value specified in the document
571+ using [YAML metadata blocks][Extension: `yaml_metadata_block`].
529572 Values will be parsed as YAML boolean or string values. If no value is
530573 specified, the value will be treated as Boolean true. Like
531574 `--variable`, `--metadata` causes template variables to be set.
532575 But unlike `--variable`, `--metadata` affects the metadata of the
533576 underlying document (which is accessible from filters and may be
534− printed in some output formats).
577+ printed in some output formats) and metadata values will be escaped
578+ when inserted into the template.
535579
536580`-p`, `--preserve-tabs`
537581
@@ -598,7 +642,8 @@ General writer options
598642: Produce output with an appropriate header and footer (e.g. a
599643 standalone HTML, LaTeX, TEI, or RTF file, not a fragment). This option
600644 is set automatically for `pdf`, `epub`, `epub3`, `fb2`, `docx`, and `odt`
601− output.
645+ output. For `native` output, this option causes metadata to
646+ be included; otherwise, metadata is suppressed.
602647
603648`--template=`*FILE*
604649
@@ -795,9 +840,10 @@ Options affecting specific writers
795840
796841`--ascii`
797842
798−: Use only ASCII characters in output. Currently supported only for
799− HTML and DocBook output (which uses numerical entities instead of
800− UTF-8 when this option is selected).
843+: Use only ASCII characters in output. Currently supported for
844+ XML and HTML formats (which use numerical entities instead of
845+ UTF-8 when this option is selected) and for groff ms and man
846+ (which use hexadecimal escapes).
801847
802848`--reference-links`
803849
@@ -1171,54 +1217,8 @@ of the following options.
11711217 not specified, a link to the KaTeX CDN will be inserted. Note that this
11721218 option does not imply `--katex`.
11731219
1174−`-m` [*URL*], `--latexmathml`[`=`*URL*]
1175−
1176−: *Deprecated.*
1177− Use the [LaTeXMathML] script to display embedded TeX math in HTML output.
1178− TeX math will be displayed between `$` or `$$` characters and put in
1179− `<span>` tags with class `LaTeX`. The LaTeXMathML JavaScript will then
1180− change it to MathML. Note that currently only Firefox and Safari
1181− (and select e-book readers) natively support MathML.
1182− To insert a link the `LaTeXMathML.js` script, provide a *URL*.
1183−
1184−`--jsmath`[`=`*URL*]
1185−
1186−: *Deprecated.*
1187− Use [jsMath] (the predecessor of MathJax) to display embedded TeX
1188− math in HTML output. TeX math will be put inside `<span>` tags
1189− (for inline math) or `<div>` tags (for display math) with class
1190− `math` and rendered by the jsMath script. The *URL* should point to
1191− the script (e.g. `jsMath/easy/load.js`); if provided, it will be linked
1192− to in the header of standalone HTML documents. If a *URL* is not provided,
1193− no link to the jsMath load script will be inserted; it is then
1194− up to the author to provide such a link in the HTML template.
1195−
1196−`--gladtex`
1197−
1198−: *Deprecated.*
1199− Enclose TeX math in `<eq>` tags in HTML output. The resulting HTML
1200− can then be processed by [gladTeX] to produce images of the typeset
1201− formulas and an HTML file with links to these images.
1202− So, the procedure is:
1203−
1204− pandoc -s --gladtex input.md -o myfile.htex
1205− gladtex -d myfile-images myfile.htex
1206− # produces myfile.html and images in myfile-images
1207−
1208−`--mimetex`[`=`*URL*]
1209−
1210−: *Deprecated.*
1211− Render TeX math using the [mimeTeX] CGI script, which generates an
1212− image for each TeX formula. This should work in all browsers. If
1213− *URL* is not specified, it is assumed that the script is at
1214− `/cgi-bin/mimetex.cgi`.
1215−
12161220[MathML]: http://www.w3.org/Math/
1217−[LaTeXMathML]: http://math.etsu.edu/LaTeXMathML/
1218−[jsMath]: http://www.math.union.edu/~dpvc/jsmath/
12191221[MathJax]: https://www.mathjax.org
1220−[gladTeX]: http://ans.hsh.no/home/mgg/gladtex/
1221−[mimeTeX]: http://www.forkosh.com/mimetex.html
12221222[KaTeX]: https://github.com/Khan/KaTeX
12231223
12241224Options for wrapper scripts
@@ -1266,23 +1266,22 @@ directory (see `--data-dir`, above). *Exceptions:*
12661266- For `pdf` output, customize the `default.latex` template
12671267 (or the `default.context` template, if you use `-t context`,
12681268 or the `default.ms` template, if you use `-t ms`, or the
1269− `default.html5` template, if you use `-t html5`).
1269+ `default.html` template, if you use `-t html`).
12701270- `docx` has no template (however, you can use
12711271 `--reference-doc` to customize the output).
12721272
12731273Templates contain *variables*, which allow for the inclusion of
1274−arbitrary information at any point in the file. Variables may be set
1275−within the document using [YAML metadata blocks][Extension:
1276−`yaml_metadata_block`]. They may also be set at the
1277−command line using the `-V/--variable` option: variables set in this
1278−way override metadata fields with the same name.
1274+arbitrary information at any point in the file. They may be set at the
1275+command line using the `-V/--variable` option. If a variable is not set,
1276+pandoc will look for the key in the document's metadata – which can be set
1277+using either [YAML metadata blocks][Extension: `yaml_metadata_block`]
1278+or with the `--metadata` option.
12791279
12801280Variables set by pandoc
12811281-----------------------
12821282
12831283Some variables are set automatically by pandoc. These vary somewhat
1284−depending on the output format, but include metadata fields as well
1285−as the following:
1284+depending on the output format, but include the following:
12861285
12871286`sourcefile`, `outputfile`
12881287: source and destination filenames, as given on the command line.
@@ -1467,6 +1466,9 @@ LaTeX variables are used when [creating a PDF].
14671466: option for document class, e.g. `oneside`; may be repeated
14681467 for multiple options
14691468
1469+`beameroption`
1470+: In beamer, add extra beamer option with `\setbeameroption{}`
1471+
14701472`geometry`
14711473: option for [`geometry`] package, e.g. `margin=1in`;
14721474 may be repeated for multiple options
@@ -1624,12 +1626,22 @@ Variables for ConTeXt
16241626`lof`, `lot`
16251627: include list of figures, list of tables
16261628
1629+`pdfa`
1630+: adds to the preamble the setup necessary to generate PDF/A-1b:2005.
1631+ To successfully generate PDF/A the required ICC color profiles have to
1632+ be available and the content and all included files (such as images)
1633+ have to be standard conforming. The ICC profiles can be obtained
1634+ from [ConTeXt ICC Profiles]. See also [ConTeXt PDFA] for more
1635+ details.
1636+
16271637[ConTeXt Paper Setup]: http://wiki.contextgarden.net/PaperSetup
16281638[ConTeXt Layout]: http://wiki.contextgarden.net/Layout
16291639[ConTeXt Font Switching]: http://wiki.contextgarden.net/Font_Switching
16301640[ConTeXt Color]: http://wiki.contextgarden.net/Color
16311641[ConTeXt Headers and Footers]: http://wiki.contextgarden.net/Headers_and_Footers
16321642[ConTeXt Indentation]: http://wiki.contextgarden.net/Indentation
1643+[ConTeXt ICC Profiles]: http://wiki.contextgarden.net/PDFX#ICC_profiles
1644+[ConTeXt PDFA]: http://wiki.contextgarden.net/PDF/A
16331645[`setupwhitespace`]: http://wiki.contextgarden.net/Command/setupwhitespace
16341646[`setupinterlinespace`]: http://wiki.contextgarden.net/Command/setupinterlinespace
16351647[`setuppagenumbering`]: http://wiki.contextgarden.net/Command/setuppagenumbering
@@ -1689,10 +1701,24 @@ Templates may contain conditionals. The syntax is as follows:
16891701 Y
16901702 $endif$
16911703
1692−This will include `X` in the template if `variable` has a non-null
1693−value; otherwise it will include `Y`. `X` and `Y` are placeholders for
1694−any valid template text, and may include interpolated variables or other
1695−conditionals. The `$else$` section may be omitted.
1704+This will include `X` in the template if `variable` has a truthy
1705+value; otherwise it will include `Y`. Here a truthy value is any
1706+of the following:
1707+
1708+- a string that is not entirely white space,
1709+- a non-empty array where the first value is truthy,
1710+- any number (including zero),
1711+- any object,
1712+- the boolean `true` (to specify the boolean `true`
1713+ value using YAML metadata or the `--metadata` flag,
1714+ use `y`, `Y`, `yes`, `Yes`, `YES`, `true`, `True`,
1715+ `TRUE`, `on`, `On`, or `ON`; with the `--variable`
1716+ flag, simply omit a value for the variable, e.g.
1717+ `--variable draft`).
1718+
1719+`X` and `Y` are placeholders for any valid template text,
1720+and may include interpolated variables or other conditionals.
1721+The `$else$` section may be omitted.
16961722
16971723When variables can have multiple values (for example, `author` in
16981724a multi-author document), you can use the `$for$` keyword:
@@ -1954,9 +1980,9 @@ ordinary HTML (without bird tracks).
19541980writes HTML with the Haskell code in bird tracks, so it can be copied
19551981and pasted as literate Haskell source.
19561982
1957−Note that GHC expects the bird tracks in the first column, so indentend literate
1958−code blocks (e.g. inside an itemized environment) will not be picked up by the
1959−Haskell compiler.
1983+Note that GHC expects the bird tracks in the first column, so indented
1984+literate code blocks (e.g. inside an itemized environment) will not be
1985+picked up by the Haskell compiler.
19601986
19611987Other extensions
19621988----------------
@@ -1972,7 +1998,7 @@ input formats
19721998: `docx`, `html`
19731999
19742000output formats
1975−: `markdown`, `docx`, `odt`, `opendocument`, `html`
2001+: `docx`, `odt`, `opendocument`, `html`
19762002
19772003#### Extension: `styles` #### {#ext-styles}
19782004
@@ -3086,7 +3112,8 @@ the [`raw_attribute` extension](#extension-raw_attribute)), or it
30863112will be interpreted as markdown. For example:
30873113
30883114 header-includes:
3089− - ```{=latex}
3115+ - |
3116+ ```{=latex}
30903117 \let\oldsection\section
30913118 \renewcommand{\section}[1]{\clearpage\oldsection{#1}}
30923119 ```
@@ -3405,9 +3432,24 @@ And the following produces a raw `html` inline element:
34053432
34063433 This is `<a>html</a>`{=html}
34073434
3435+This can be useful to insert raw xml into `docx` documents, e.g.
3436+a pagebreak:
3437+
3438+ ```{=openxml}
3439+ <w:p>
3440+ <w:r>
3441+ <w:br w:type="page"/>
3442+ </w:r>
3443+ </w:p>
3444+ ```
3445+
34083446The format name should match the target format name (see
34093447`-t/--to`, above, for a list, or use `pandoc
3410−--list-output-formats`).
3448+--list-output-formats`). Use `openxml` for `docx` output,
3449+`opendocument` for `odt` output, `html5` for `epub3` output,
3450+`html4` for `epub2` output, and `latex`, `beamer`,
3451+`ms`, or `html5` for `pdf` output (depending on what you
3452+use for `--pdf-engine`).
34113453
34123454This extension presupposes that the relevant kind of
34133455inline code or fenced code block is enabled. Thus, for
@@ -4384,6 +4426,50 @@ the [Beamer User's Guide] may also be used: `allowdisplaybreaks`,
43844426`allowframebreaks`, `b`, `c`, `t`, `environment`, `label`, `plain`,
43854427`shrink`.
43864428
4429+Background in reveal.js
4430+-----------------------
4431+
4432+Background images can be added to self-contained reveal.js slideshows.
4433+
4434+For the same image on every slide, use the reveal.js configuration
4435+option `parallaxBackgroundImage` either in the YAML metadata block
4436+or as a command-line variable. You can also set
4437+`parallaxBackgroundHorizontal` and `parallaxBackgroundVertical` the same
4438+way and must also set `parallaxBackgroundSize` to have your values
4439+take effect.
4440+
4441+To set an image for a particular slide, add
4442+`{data-background-image="/path/to/image"}`
4443+to the first slide-level header on the slide (which may even be empty).
4444+
4445+In reveal.js's overview mode, the parallaxBackgroundImage will show up
4446+only on the first slide.
4447+
4448+Other background settings also work on individual slides, including
4449+`data-background-size`, `data-background-repeat`, `data-background-color`,
4450+`data-transition`, and `data-transition-speed`.
4451+
4452+See the [reveal.js
4453+documentation](https://github.com/hakimel/reveal.js#slide-backgrounds)
4454+for more details.
4455+
4456+For example:
4457+
4458+```
4459+---
4460+title: My Slideshow
4461+parallaxBackgroundImage: /path/to/my/background_image.png
4462+---
4463+
4464+## Slide One
4465+
4466+Slide 1 has background_image.png as its background.
4467+
4468+## {data-background-image="/path/to/special_image.jpg"}
4469+
4470+Slide 2 has a special image for its background, even though the header has no content.
4471+```
4472+
43874473Creating EPUBs with pandoc
43884474==========================
43894475
@@ -4562,8 +4648,8 @@ And with the extension:
45624648 :::
45634649
45644650 ::: {custom-style="BodyText"}
4565− This is text with an [*emphasized*]{custom-style="Emphatic"} text style.
4566− And this is text with a [**strengthened**]{custom-style="Strengthened"}
4651+ This is text with an [emphasized]{custom-style="Emphatic"} text style.
4652+ And this is text with a [strengthened]{custom-style="Strengthened"}
45674653 text style.
45684654 :::
45694655
Makefile+13−6
@@ -54,9 +54,9 @@ debpkg: man/pandoc.1
5454macospkg: man/pandoc.1
5555 ./macos/make_macos_package.sh
5656
57−winpkg: pandoc-$(version)-windows.msi pandoc-$(version)-windows.zip
57+winpkg: pandoc-$(version)-windows-i386.msi pandoc-$(version)-windows-i386.zip pandoc-$(version)-windows-x86_64.msi pandoc-$(version)-windows-x86_64.zip
5858
59−pandoc-$(version)-windows.zip: pandoc-$(version)-windows.msi
59+pandoc-$(version)-windows-%.zip: pandoc-$(version)-windows-%.msi
6060 -rm -rf wintmp && \
6161 msiextract -C wintmp $< && \
6262 cd wintmp/"Program Files" && \
@@ -66,10 +66,17 @@ pandoc-$(version)-windows.zip: pandoc-$(version)-windows.msi
6666 cd ../.. && \
6767 rm -rf wintmp
6868
69−pandoc-$(version)-windows.msi:
70− wget 'https://ci.appveyor.com/api/projects/jgm/pandoc/artifacts/windows/pandoc-windows-i386.msi?branch=$(BRANCH)' -O pandoc.msi && \
71− osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2019.p12 -in pandoc.msi -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass
72− rm pandoc.msi
69+pandoc-$(version)-windows-%.msi: pandoc-windows-%.msi
70+ osslsigncode sign -pkcs12 ~/Private/ComodoCodeSigning.exp2019.p12 -in $< -i http://johnmacfarlane.net/ -t http://timestamp.comodoca.com/ -out $@ -askpass
71+ rm $<
72+
73+pandoc-windows-i386.msi:
74+ JOBID=$(shell curl 'https://ci.appveyor.com/api/projects/jgm/pandoc' | jq -r '.build.jobs[0].jobId') && \
75+ wget "https://ci.appveyor.com/api/buildjobs/$$JOBID/artifacts/windows%2F$@" -O $@
76+
77+pandoc-windows-x86_64.msi:
78+ JOBID=$(shell curl 'https://ci.appveyor.com/api/projects/jgm/pandoc' | jq -r '.build.jobs[1].jobId') && \
79+ wget "https://ci.appveyor.com/api/buildjobs/$$JOBID/artifacts/windows%2F$@" -O $@
7380
7481man/pandoc.1: MANUAL.txt man/pandoc.1.template
7582 pandoc $< -f markdown-smart -t man -s --template man/pandoc.1.template \
README.md+142−84
@@ -22,93 +22,153 @@ groups](https://img.shields.io/badge/pandoc-discuss-red.svg?style=social)](https
2222
2323## The universal markup converter
2424
25−<div id="description">
26−
27−Pandoc is a [Haskell](https://www.haskell.org) library for converting
28−from one markup format to another, and a command-line tool that uses
29−this library.
30−
31−Pandoc can read
32−[Markdown](http://daringfireball.net/projects/markdown/),
33−[CommonMark](http://commonmark.org), [PHP Markdown
34−Extra](https://michelf.ca/projects/php-markdown/extra/),
35−[GitHub-Flavored
36−Markdown](https://help.github.com/articles/github-flavored-markdown/),
37−[MultiMarkdown](http://fletcherpenney.net/multimarkdown/), and (subsets
38−of) [Textile](http://redcloth.org/textile),
39−[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html),
40−[HTML](http://www.w3.org/html/), [LaTeX](http://latex-project.org),
41−[MediaWiki markup](https://www.mediawiki.org/wiki/Help:Formatting),
42−[TWiki markup](http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules),
43−[TikiWiki
44−markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax),
45−[Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0), [Haddock
46−markup](https://www.haskell.org/haddock/doc/html/ch03s08.html),
47−[OPML](http://dev.opml.org/spec2.html), [Emacs Org
48−mode](http://orgmode.org), [DocBook](http://docbook.org),
49−[JATS](https://jats.nlm.nih.gov),
50−[Muse](https://amusewiki.org/library/manual),
51−[txt2tags](http://txt2tags.org), [Vimwiki](https://vimwiki.github.io),
52−[EPUB](http://idpf.org/epub),
53−[ODT](http://en.wikipedia.org/wiki/OpenDocument), and [Word
54−docx](https://en.wikipedia.org/wiki/Office_Open_XML).
55−
56−Pandoc can write plain text,
57−[Markdown](http://daringfireball.net/projects/markdown/),
58−[CommonMark](http://commonmark.org), [PHP Markdown
59−Extra](https://michelf.ca/projects/php-markdown/extra/),
60−[GitHub-Flavored
61−Markdown](https://help.github.com/articles/github-flavored-markdown/),
62−[MultiMarkdown](http://fletcherpenney.net/multimarkdown/),
63−[reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html),
64−[XHTML](http://www.w3.org/TR/xhtml1/),
65−[HTML5](http://www.w3.org/TR/html5/), [LaTeX](http://latex-project.org)
66−(including [`beamer`](https://ctan.org/pkg/beamer) slide shows),
67−[ConTeXt](http://www.contextgarden.net/),
68−[RTF](http://en.wikipedia.org/wiki/Rich_Text_Format),
69−[OPML](http://dev.opml.org/spec2.html), [DocBook](http://docbook.org),
70−[JATS](https://jats.nlm.nih.gov),
71−[OpenDocument](http://opendocument.xml.org),
72−[ODT](http://en.wikipedia.org/wiki/OpenDocument), [Word
73−docx](https://en.wikipedia.org/wiki/Office_Open_XML), [GNU
74−Texinfo](http://www.gnu.org/software/texinfo/), [MediaWiki
75−markup](https://www.mediawiki.org/wiki/Help:Formatting), [DokuWiki
76−markup](https://www.dokuwiki.org/dokuwiki), [ZimWiki
77−markup](http://zim-wiki.org/manual/Help/Wiki_Syntax.html), [Haddock
78−markup](https://www.haskell.org/haddock/doc/html/ch03s08.html),
79−[EPUB](http://idpf.org/epub) (v2 or v3),
80−[FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1),
81−[Textile](http://redcloth.org/textile), [groff
82−man](http://man7.org/linux/man-pages/man7/groff_man.7.html), [groff
83−ms](http://man7.org/linux/man-pages/man7/groff_ms.7.html), [Emacs Org
84−mode](http://orgmode.org),
85−[AsciiDoc](http://www.methods.co.nz/asciidoc/), [InDesign
86−ICML](http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf),
87−[TEI Simple](https://github.com/TEIC/TEI-Simple),
88−[Muse](https://amusewiki.org/library/manual),
89−[PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint) slide
90−shows and [Slidy](http://www.w3.org/Talks/Tools/Slidy/),
91−[Slideous](http://goessner.net/articles/slideous/),
92−[DZSlides](http://paulrouget.com/dzslides/),
93−[reveal.js](http://lab.hakim.se/reveal-js/) or
94−[S5](http://meyerweb.com/eric/tools/s5/) HTML slide shows. It can also
95−produce [PDF](https://www.adobe.com/pdf/) output on systems where LaTeX,
96−ConTeXt, `pdfroff`, `wkhtmltopdf`, `prince`, or `weasyprint` is
97−installed.
25+Pandoc is a [Haskell](http://haskell.org) library for converting from
26+one markup format to another, and a command-line tool that uses this
27+library. It can convert *from*
28+
29+<div id="input-formats">
30+
31+ - `commonmark` ([CommonMark](http://commonmark.org) Markdown)
32+ - `creole` ([Creole 1.0](http://www.wikicreole.org/wiki/Creole1.0))
33+ - `docbook` ([DocBook](http://docbook.org))
34+ - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
35+ - `epub` ([EPUB](http://idpf.org/epub))
36+ - `fb2`
37+ ([FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1)
38+ e-book)
39+ - `gfm` ([GitHub-Flavored
40+ Markdown](https://help.github.com/articles/github-flavored-markdown/)),
41+ or `markdown_github`, which provides deprecated and less accurate
42+ support for Github-Flavored Markdown; please use `gfm` instead,
43+ unless you need to use extensions other than `smart`.
44+ - `haddock` ([Haddock
45+ markup](https://www.haskell.org/haddock/doc/html/ch03s08.html))
46+ - `html` ([HTML](http://www.w3.org/html/))
47+ - `jats` ([JATS](https://jats.nlm.nih.gov) XML)
48+ - `json` (JSON version of native AST)
49+ - `latex` ([LaTeX](http://latex-project.org))
50+ - `markdown` ([Pandoc’s Markdown](#pandocs-markdown))
51+ - `markdown_mmd`
52+ ([MultiMarkdown](http://fletcherpenney.net/multimarkdown/))
53+ - `markdown_phpextra` ([PHP Markdown
54+ Extra](https://michelf.ca/projects/php-markdown/extra/))
55+ - `markdown_strict` (original unextended
56+ [Markdown](http://daringfireball.net/projects/markdown/))
57+ - `mediawiki` ([MediaWiki
58+ markup](https://www.mediawiki.org/wiki/Help:Formatting))
59+ - `muse` ([Muse](https://amusewiki.org/library/manual))
60+ - `native` (native Haskell)
61+ - `odt` ([ODT](http://en.wikipedia.org/wiki/OpenDocument))
62+ - `opml` ([OPML](http://dev.opml.org/spec2.html))
63+ - `org` ([Emacs Org mode](http://orgmode.org))
64+ - `rst`
65+ ([reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html))
66+ - `t2t` ([txt2tags](http://txt2tags.org))
67+ - `textile` ([Textile](http://redcloth.org/textile))
68+ - `tikiwiki` ([TikiWiki
69+ markup](https://doc.tiki.org/Wiki-Syntax-Text#The_Markup_Language_Wiki-Syntax))
70+ - `twiki` ([TWiki
71+ markup](http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules))
72+ - `vimwiki` ([Vimwiki](https://vimwiki.github.io))
73+
74+</div>
75+
76+It can convert *to*
77+
78+<div id="output-formats">
79+
80+ - `asciidoc` ([AsciiDoc](http://www.methods.co.nz/asciidoc/))
81+ - `beamer` ([LaTeX beamer](https://ctan.org/pkg/beamer) slide show)
82+ - `commonmark` ([CommonMark](http://commonmark.org) Markdown)
83+ - `context` ([ConTeXt](http://www.contextgarden.net/))
84+ - `docbook` or `docbook4` ([DocBook](http://docbook.org) 4)
85+ - `docbook5` (DocBook 5)
86+ - `docx` ([Word docx](https://en.wikipedia.org/wiki/Office_Open_XML))
87+ - `dokuwiki` ([DokuWiki markup](https://www.dokuwiki.org/dokuwiki))
88+ - `epub` or `epub3` ([EPUB](http://idpf.org/epub) v3 book)
89+ - `epub2` (EPUB v2)
90+ - `fb2`
91+ ([FictionBook2](http://www.fictionbook.org/index.php/Eng:XML_Schema_Fictionbook_2.1)
92+ e-book)
93+ - `gfm` ([GitHub-Flavored
94+ Markdown](https://help.github.com/articles/github-flavored-markdown/)),
95+ or `markdown_github`, which provides deprecated and less accurate
96+ support for Github-Flavored Markdown; please use `gfm` instead,
97+ unless you use extensions that do not work with `gfm`.
98+ - `haddock` ([Haddock
99+ markup](https://www.haskell.org/haddock/doc/html/ch03s08.html))
100+ - `html` or `html5` ([HTML](http://www.w3.org/html/), i.e.
101+ [HTML5](http://www.w3.org/TR/html5/)/XHTML [polyglot
102+ markup](https://www.w3.org/TR/html-polyglot/))
103+ - `html4` ([XHTML](http://www.w3.org/TR/xhtml1/) 1.0 Transitional)
104+ - `icml` ([InDesign
105+ ICML](http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/indesign/sdk/cs6/idml/idml-cookbook.pdf))
106+ - `jats` ([JATS](https://jats.nlm.nih.gov) XML)
107+ - `json` (JSON version of native AST)
108+ - `latex` ([LaTeX](http://latex-project.org))
109+ - `man` ([groff
110+ man](http://man7.org/linux/man-pages/man7/groff_man.7.html))
111+ - `markdown` ([Pandoc’s Markdown](#pandocs-markdown))
112+ - `markdown_mmd`
113+ ([MultiMarkdown](http://fletcherpenney.net/multimarkdown/))
114+ - `markdown_phpextra` ([PHP Markdown
115+ Extra](https://michelf.ca/projects/php-markdown/extra/))
116+ - `markdown_strict` (original unextended
117+ [Markdown](http://daringfireball.net/projects/markdown/))
118+ - `mediawiki` ([MediaWiki
119+ markup](https://www.mediawiki.org/wiki/Help:Formatting))
120+ - `ms` ([groff
121+ ms](http://man7.org/linux/man-pages/man7/groff_ms.7.html))
122+ - `muse` ([Muse](https://amusewiki.org/library/manual)),
123+ - `native` (native Haskell),
124+ - `odt` ([OpenOffice text
125+ document](http://en.wikipedia.org/wiki/OpenDocument))
126+ - `opml` ([OPML](http://dev.opml.org/spec2.html))
127+ - `opendocument` ([OpenDocument](http://opendocument.xml.org))
128+ - `org` ([Emacs Org mode](http://orgmode.org))
129+ - `plain` (plain text),
130+ - `pptx`
131+ ([PowerPoint](https://en.wikipedia.org/wiki/Microsoft_PowerPoint)
132+ slide show)
133+ - `rst`
134+ ([reStructuredText](http://docutils.sourceforge.net/docs/ref/rst/introduction.html))
135+ - `rtf` ([Rich Text
136+ Format](http://en.wikipedia.org/wiki/Rich_Text_Format))
137+ - `texinfo` ([GNU Texinfo](http://www.gnu.org/software/texinfo/))
138+ - `textile` ([Textile](http://redcloth.org/textile))
139+ - `slideous` ([Slideous](http://goessner.net/articles/slideous/) HTML
140+ and JavaScript slide show)
141+ - `slidy` ([Slidy](http://www.w3.org/Talks/Tools/Slidy/) HTML and
142+ JavaScript slide show)
143+ - `dzslides` ([DZSlides](http://paulrouget.com/dzslides/) HTML5 +
144+ JavaScript slide show),
145+ - `revealjs` ([reveal.js](http://lab.hakim.se/reveal-js/) HTML5 +
146+ JavaScript slide show)
147+ - `s5` ([S5](http://meyerweb.com/eric/tools/s5/) HTML and JavaScript
148+ slide show)
149+ - `tei` ([TEI Simple](https://github.com/TEIC/TEI-Simple))
150+ - `zimwiki` ([ZimWiki
151+ markup](http://zim-wiki.org/manual/Help/Wiki_Syntax.html))
152+ - the path of a custom lua writer, see [Custom
153+ writers](#custom-writers) below
154+
155+</div>
156+
157+Pandoc can also produce PDF output via LaTeX, Groff ms, or HTML.
98158
99159Pandoc’s enhanced version of Markdown includes syntax for tables,
100−definition lists, metadata blocks, `Div` blocks, footnotes and
101−citations, embedded LaTeX (including math), Markdown inside HTML block
102−elements, and much more. These enhancements, described further under
103−Pandoc’s Markdown, can be disabled using the `markdown_strict` format.
160+definition lists, metadata blocks, footnotes, citations, math, and much
161+more. See the User’s Manual below under [Pandoc’s
162+Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown).
104163
105164Pandoc has a modular design: it consists of a set of readers, which
106165parse text in a given format and produce a native representation of the
107−document (like an *abstract syntax tree* or AST), and a set of writers,
108−which convert this native representation into a target format. Thus,
109−adding an input or output format requires only adding a reader or
110−writer. Users can also run custom [pandoc
111−filters](http://pandoc.org/filters.html) to modify the intermediate AST.
166+document (an *abstract syntax tree* or AST), and a set of writers, which
167+convert this native representation into a target format. Thus, adding an
168+input or output format requires only adding a reader or writer. Users
169+can also run custom pandoc filters to modify the intermediate AST (see
170+the documentation for [filters](https://pandoc.org/filters.html) and
171+[lua filters](https://pandoc.org/lua-filters.html)).
112172
113173Because pandoc’s intermediate representation of a document is less
114174expressive than many of the formats it converts between, one should not
@@ -120,8 +180,6 @@ While conversions from pandoc’s Markdown to all formats aspire to be
120180perfect, conversions from formats more expressive than pandoc’s Markdown
121181can be expected to be lossy.
122182
123−</div>
124−
125183## Installing
126184
127185Here’s [how to install pandoc](INSTALL.md).
README.template+37−1
@@ -19,9 +19,44 @@ Pandoc
1919The universal markup converter
2020------------------------------
2121
22−::: description
22+Pandoc is a [Haskell] library for converting from one markup format to
23+another, and a command-line tool that uses this library. It can convert *from*
24+
25+::: {#input-formats}
2326:::
2427
28+It can convert *to*
29+
30+::: {#output-formats}
31+:::
32+
33+Pandoc can also produce PDF output via LaTeX, Groff ms, or HTML.
34+
35+Pandoc's enhanced version of Markdown includes syntax for tables,
36+definition lists, metadata blocks, footnotes, citations, math,
37+and much more. See the User's Manual below under
38+[Pandoc's Markdown](https://pandoc.org/MANUAL.html#pandocs-markdown).
39+
40+Pandoc has a modular design: it consists of a set of readers, which parse
41+text in a given format and produce a native representation of the document
42+(an _abstract syntax tree_ or AST), and a set of writers, which convert
43+this native representation into a target format. Thus, adding an input
44+or output format requires only adding a reader or writer. Users can also
45+run custom pandoc filters to modify the intermediate AST (see
46+the documentation for [filters](https://pandoc.org/filters.html)
47+and [lua filters](https://pandoc.org/lua-filters.html)).
48+
49+Because pandoc's intermediate representation of a document is less
50+expressive than many of the formats it converts between, one should
51+not expect perfect conversions between every format and every other.
52+Pandoc attempts to preserve the structural elements of a document, but
53+not formatting details such as margin size. And some document elements,
54+such as complex tables, may not fit into pandoc's simple document
55+model. While conversions from pandoc's Markdown to all formats aspire
56+to be perfect, conversions from formats more expressive than pandoc's
57+Markdown can be expected to be lossy.
58+
59+
2560Installing
2661----------
2762
@@ -52,3 +87,4 @@ License
5287any kind. (See COPYRIGHT for full copyright and warranty notices.)
5388
5489[GPL]: http://www.gnu.org/copyleft/gpl.html "GNU General Public License"
90+[Haskell]: http://haskell.org
appveyor.yml+5−4
@@ -1,3 +1,4 @@
1+image: Visual Studio 2013
12clone_folder: "c:\\pandoc"
23environment:
34 global:
@@ -10,10 +11,10 @@ environment:
1011 STACK_ROOT: "c:\\sr32"
1112 STACK: "%STACK_ROOT%\\stack.exe"
1213 STACK_FLAGS: "--flag=hslua:lua_32bits"
13−# - STACK_VERSION: "windows-x86_64"
14−# STACK_ROOT: "c:\\sr64"
15−# STACK: "%STACK_ROOT%\\stack.exe"
16−# STACK_FLAGS: ""
14+ - STACK_VERSION: "windows-x86_64"
15+ STACK_ROOT: "c:\\sr64"
16+ STACK: "%STACK_ROOT%\\stack.exe"
17+ STACK_FLAGS: ""
1718
1819skip_commits:
1920 files:
benchmark/benchmark-pandoc.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE TupleSections #-}
23{-
34Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -16,6 +17,7 @@ You should have received a copy of the GNU General Public License
1617along with this program; if not, write to the Free Software
1718Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1819-}
20+import Prelude
1921import Text.Pandoc
2022import qualified Text.Pandoc.UTF8 as UTF8
2123import qualified Data.ByteString as B
benchmark/weigh-pandoc.hs+2
@@ -1,3 +1,5 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+import Prelude
13import Weigh
24import Text.Pandoc
35import Data.Text (Text)
changelog+707−2
@@ -1,3 +1,708 @@
1+pandoc (2.2)
2+
3+ * New input format: `fb2` (FictionBook2) (Alexander Krotov).
4+
5+ * Make `--ascii` work for all XML formats (ICML, OPML, JATS,...),
6+ and for `ms` and `man`.
7+
8+ * Remove deprecated `--latexmathml`, `--gladtex`, `--mimetex`, `--jsmath`, `-m`,
9+ `--asciimathml` options.
10+
11+ * New module Text.Pandoc.Readers.FB2, exporting readFB2 (Alexander
12+ Krotov, API change).
13+
14+ * Markdown reader:
15+
16+ + Allow empty key-value attributes, like `title=""` (#2944).
17+ + Handle table w/o following blank line in fenced div (#4560).
18+ + Remove "fallback" for `doubleQuote` parser. Previously the
19+ parser tried to be efficient -- if no end double quote was found,
20+ it would just return the contents. But this could backfire in a
21+ case `**this should "be bold**`, since the fallback would return
22+ the content `"be bold**` and the closing boldface delimiter
23+ would never be encountered.
24+ + Improve computation of the relative width of the last column in a
25+ multiline table, so we can round-trip tables without constantly
26+ shrinking the last column.
27+
28+ * EPUB reader:
29+
30+ + Fix images with space in file path (#4344).
31+
32+ * LaTeX reader:
33+
34+ + Properly resolve section numbers with `\ref` and chapters (#4529).
35+ + Parse sloppypar environment (#4517, Marc Schreiber).
36+ + Improve handling of raw LaTeX (for markdown etc.) (#4589, #4594).
37+ Previously there were some bugs in how macros were handled.
38+ + Support `\MakeUppercase`, `\MakeLowercase', `\uppercase`, `\lowercase`,
39+ and also `\MakeTextUppercase` and `\MakeTextLowercase` from textcase
40+ (#4959).
41+
42+ * Textile reader:
43+
44+ + Fixed tables with no body rows (#4513).
45+ Previously these raised an exception.
46+
47+ * Mediawiki reader:
48+
49+ + Improve table parsing (#4508). This fixes detection of table
50+ attributes and also handles `!` characters in cells.
51+
52+ * DocBook reader:
53+
54+ + Properly handle title in `section` element (#4526).
55+ Previously we just got `section_title` for `section` (though `sect1`,
56+ `sect2`, etc. were handled properly).
57+ + Read tex math as output by asciidoctor (#4569, Joe Hermaszewski).
58+
59+ * Docx reader:
60+
61+ + Combine adjacent CodeBlocks with the same attributes into
62+ a single CodeBlock. This prevents a multiline codeblock in
63+ Word from being read as different paragraphs.
64+
65+ * RST reader:
66+
67+ + Allow < 3 spaces indent under directives (#4579).
68+ + Fix anonymous redirects with backticks (#4598).
69+
70+ * Muse reader (Alexander Krotov):
71+
72+ + Add support for Text::Amuse multiline headings.
73+ + Add `<math>` tag support.
74+ + Add support for `<biblio>` and `<play>` tags.
75+ + Allow links to have empty descriptions.
76+ + Require block `<literal>` tags to be on separate lines.
77+ + Allow `-` in anchors.
78+ + Allow verse to be indented.
79+ + Allow nested footnotes.
80+ + Internal improvements.
81+
82+ * Muse writer (Alexander Krotov):
83+
84+ + Escape `>` only at the beginning of a line.
85+ + Escape `]` in image title.
86+ + Escape `]` brackets in URLs as `%5D`.
87+ + Only escape brackets when necessary.
88+ + Escape ordered list markers.
89+ + Do not escape list markers unless preceded by space.
90+ + Escape strings starting with space.
91+ + Escape semicolons and markers after line break.
92+ + Escape `;` to avoid accidental comments.
93+ + Don't break headers, line blocks and tables with line breaks.
94+ + Correctly output empty headings.
95+ + Escape horizontal rule only if at the beginning of the line.
96+ + Escape definition list terms starting with list markers.
97+ + Place header IDs before header.
98+ + Improve span writing.
99+ + Do not join Spans in normalization.
100+ + Don't align ordered list items.
101+ + Remove key-value pairs from attributes before normalization.
102+ + Enable `--wrap=preserve` for all tests by default.
103+ + Reduced `<verbatim>` tags in output.
104+ + Internal changes.
105+
106+ * RST writer:
107+
108+ + Use more consistent indentation (#4563). Previously we
109+ used an odd mix of 3- and 4-space indentation. Now we use 3-space
110+ indentation, except for ordered lists, where indentation must
111+ depend on the width of the list marker.
112+ + Flatten nested inlines (#4368, Francesco Occhipinti).
113+ Nested inlines are not valid RST syntax, so we flatten them following
114+ some readability criteria discussed in #4368.
115+
116+ * EPUB writer:
117+
118+ + Ensure that `pagetitle` is always set, even when structured titles
119+ are used. This prevents spurious warnings about empty title
120+ elements (#4486).
121+
122+ * FB2 writer (Alexander Krotov):
123+
124+ + Output links inline instead of producing notes. Previously all links
125+ were turned into footnotes with unclickable URLs inside.
126+ + Allow emphasis and notes in titles.
127+ + Don't intersperse paragraph with empty lines.
128+ + Convert metadata value `abstract` to book annotation.
129+ + Use `<empty-line />` for `HorizontalRule` rather than `LineBreak`.
130+ FB2 does not have a way to represent line breaks inside paragraphs;
131+ previously we used `<empty-line />` elements, but these are not allowed
132+ inside paragraphs.
133+
134+ * Powerpoint writer (Jesse Rosenthal):
135+
136+ + Handle Quoted Inlines (#4532).
137+ + Simplify code with `ParseXml`.
138+ + Allow fallback options when looking for placeholder type.
139+ + Check reference-doc for all layouts.
140+ + Simplify speaker notes logic.
141+ + Change notes state to a simpler per-slide value.
142+ + Remove `Maybe` from `SpeakerNotes` in `Slide`. `mempty`
143+ means no speaker notes.
144+ + Add tests for improved speaker notes.
145+ + Handle speaker notes earlier in the conversion process.
146+ + Keep notes with related blocks (#4477). Some blocks automatically
147+ split slides (imgs, tables, `column` divs). We assume that any
148+ speaker notes immediately following these are connected to these
149+ elements, and keep them with the related blocks, splitting after them.
150+ + Remove `docProps/thumbnail.jpeg` in data dir (Jesse Rosenthal, #4588).
151+ It contained a nonfree ICC color calibration profile and is not needed
152+ for production of a powerpoint document.
153+
154+ * Markdown writer:
155+
156+ + Include a blank line at the end of the row in a single-row multiline
157+ table, to prevent it from being interpreted as a simple table (#4578).
158+
159+ * CommonMark writer:
160+
161+ + Correctly ignore LaTeX raw blocks when `raw_tex` is not
162+ enabled (#4527, quasicomputational).
163+
164+ * EPUB writer:
165+
166+ + Add `epub:type="footnotes"` to notes section in EPUB3 (#4489).
167+
168+ * LaTeX writer:
169+
170+ + In beamer, don't use format specifier for default ordered lists
171+ (#4556). This gives better results for styles that put ordered list
172+ markers in boxes or circles.
173+ + Update `\lstinline` delimiters (#4369, Tim Parenti).
174+
175+ * Ms writer:
176+
177+ + Use `\f[R]` rather than `\f[]` to reset font (#4552).
178+ + Use `\f[BI]` and `\f[CB]` in headers, instead of `\f[I]` and `\f[C]`,
179+ since the header font is automatically bold (#4552).
180+ + Use `\f[CB]` rather than `\f[BC]` for monospace bold (#4552).
181+ + Create pdf anchor for a Div with an identifier (#4515).
182+ + Escape `/` character in anchor ids (#4515).
183+ + Improve escaping for anchor ids: we now use _uNNN_ instead of uNNN
184+ to avoid ambiguity.
185+
186+ * Man writer:
187+
188+ + Don't escape U+2019 as `'` (#4550).
189+
190+ * Text.Pandoc.Options:
191+
192+ + Removed `JsMath`, `LaTeXMathML`, and `GladTeX` constructors from
193+ `Text.Pandoc.Options.HTMLMathMethod` [API change].
194+
195+ * Text.Pandoc.Class:
196+
197+ + `writeMedia`: unescape URI-escaping in file path. This avoids
198+ writing things like `file%20one.png` to the file system.
199+
200+ * Text.Pandoc.Parsing:
201+
202+ + Fix `romanNumeral` parser (#4480). We previously accepted 'DDC'
203+ as 1100.
204+ + `uri`: don't treat `*` characters at end as part of URI (#4561).
205+
206+ * Text.Pandoc.MIME:
207+
208+ + Use the alias `application/eps` for EPS (#2067).
209+ This will ensure that we retain the eps extension after reading the
210+ image into a mediabag and writing it again.
211+
212+ * Text.Pandoc.PDF:
213+
214+ + Use `withTempDir` in `html2pdf`.
215+ + With `xelatex`, don't compress images til the last run (#4484).
216+ This saves time for image-heavy documents.
217+ + Don't try to convert EPS files (#2067). `pdflatex` converts them
218+ itself, and JuicyPixels can't do it.
219+ + For `pdflatex`, use a temp directory in the working directory.
220+ Otherwise we can have problems with the EPS conversion pdflatex
221+ tries to do, which can't operate on a file above the working
222+ directory without `--shell-escape`.
223+
224+ * Changes to tests to accommodate changes in pandoc-types.
225+ In <https://github.com/jgm/pandoc-types/pull/36> we changed
226+ the table builder to pad cells. This commit changes tests
227+ (and two readers) to accord with this behavior.
228+
229+ * Set default extensions for `beamer` same as `latex`.
230+
231+ * LaTeX template:
232+
233+ + Add `beameroption` variable (#4359, Étienne Bersac).
234+ + Use `pgfpages` package; this is needed for notes on second
235+ screen in beamer (Étienne Bersac).
236+ + Add `background-image` variable (#4601, John Muccigrosso).
237+
238+ * reveal.js template: Add `background-image` variable (#4600,
239+ John Muccigrosso).
240+
241+ * ms template: Fix date. Previously `.ND` was used, but this only
242+ works if you have a title page, which we don't. Thanks to @teoric.
243+
244+ * Removed pragmas for unused extensions (#4506, Anabra).
245+
246+ * Fix bash completion for `--print-default-data-file` (#4549).
247+ Previously this looked in the filesystem, even if pandoc
248+ was compiled with `embed_data_files` (and sometimes it looked
249+ in a nonexistent build directory). Now the bash completion
250+ script just includes a hard-coded list of data file names.
251+
252+ * MANUAL:
253+
254+ + Clarify template vs metadata variables (#4501, Mauro Bieg).
255+ + Fix raw content example (#4479, Mauro Bieg).
256+ + Specify that you use html for raw output in epub.
257+ + Add examples for raw docx blocks (#4472, Tristan Stenner).
258+ The documentation states that the target format name should match
259+ the output format, which isn't the case for `docx`/`openxml` and
260+ some others.
261+ + Don't say that `empty_paragraphs` affects markdown output (#4540).
262+ + Consolidate input/output format documentation (#4577, Mauro Bieg).
263+
264+ * New README template. Take in/out formats from manual.
265+
266+ * Fix example in lua-filters docs (#4459, HeirOfNorton).
267+
268+ * Use the `-threaded` GHC flag when building benchmarks (#4587,
269+ Francesco Occhipinti).
270+
271+ * Bump temporary upper bound to 1.4.
272+
273+ * Use pandoc-citeproc 0.14.3.1.
274+
275+ * Use texmath-0.10.1.2 (fixes escapes in math in ms, #4597).
276+
277+ * Removed old lib directory. This was used for something long ago,
278+ but plays no role now.
279+
280+ * Removed unneeded data file `LaTeXMathML.js`.
281+
282+ * Create 64- and 32-bit versions of Windows binary packages.
283+
284+pandoc (2.1.3)
285+
286+ * Docx reader (Jesse Rosenthal):
287+
288+ + Add tests for nested smart tags.
289+ + Parse nested smart tags.
290+ + Make unwrapSDT into a general `unwrap` function that can unwrap both
291+ nested SDT tags and smartTags. This makes the SmartTags constructor in
292+ the Docx type unnecessary, so we remove it (#4446).
293+ + Remove unused `docxWarnings` (Alexander Krotov).
294+
295+ * RST reader: Allow unicode bullet characters (#4454).
296+
297+ * Haddock reader: Better table handling, using haddock-library's
298+ new table support, if compiled against a version that
299+ includes it. Note that tables with col/rowspans will not
300+ translate well into Pandoc.
301+
302+ * Muse reader (Alexander Krotov):
303+
304+ + Require closing tag to have the same indentation as opening.
305+ + Do not reparse blocks inside unclosed block tag (#4425).
306+ + Parse `<class>` tag (supported by Emacs Muse).
307+ + Do not produce empty Str element for unindented verse lines.
308+ + Don't allow footnote references inside links.
309+ + Allow URL to be empty.
310+ + Require that comment semicolons are in the first column (#4551).
311+ + Various internal improvements.
312+
313+ * LaTeX reader:
314+
315+ + Add support to parse unit string of `\SI` command (closes #4296,
316+ Marc Schreiber).
317+
318+ * Haddock writer: In the writer, we now render tables always as
319+ grid tables, since Haddock supports these.
320+
321+ * DokuWiki writer: rewrite backSlashLineBreaks (#4445, Mauro Bieg).
322+
323+ * Docx writer: Fixed formatting of `DefaultStyle` ordered lists in
324+ docx writer. We want decimal for the top level, not lower roman.
325+
326+ * RST writer:
327+
328+ + Strip whitespace at beginning and ending of inline containers
329+ (#4327, Francesco Occhipinti).
330+ + Filter out empty inline containers (#4434). There is nothing in
331+ RST that corresponds to e.g. `Emph []`, so we just ignore elements
332+ like this (Francesco Occhipinti).
333+
334+ * Muse writer (Alexander Krotov):
335+
336+ + Support spans with anchors.
337+ + Replace smallcaps with emphasis before normalization.
338+ + Output smallcaps as emphasis.
339+ + Expand Cite before list normalization.
340+ + Write empty inline lists as `<verbatim></verbatim>`.
341+ + Remove empty Str from the beginning of inline lists during normalization.
342+ + Escape "-" to avoid creating bullet lists.
343+ + Fix math expansion for more than one expression per paragraph.
344+ + Expand math before inline list normalization.
345+
346+ * Dokuwiki writer: fix LineBreaks in Tables (#4313, Mauro Bieg).
347+
348+ * Ms writer:
349+
350+ + Asciify pdf anchors, since unicode anchors don't work (#4436).
351+ Internal links should be converted automatically, so this shouldn't
352+ affect users directly.
353+ + Don't escape hyphens as `\-`; that's for a minus sign (#4467).
354+
355+ * Beamer writer: put hyperlink after `\begin{frame}` and not in the title
356+ (#4307). If it's in the title, then we get a titlebar on slides with
357+ the `plain` attribute, when the id is non-null. This fixes a regression
358+ in 2.0.
359+
360+ * EPUB writer: Remove notes from TOC in nav.xhtml (#4453, Mauro Bieg).
361+
362+ * JATS writer: Remove extraneous, significant whitespace (#4335,
363+ Nokome Bentley).
364+
365+ * html2pdf: inject base tag wih current working directory (#4413, Mauro
366+ Bieg). This helps ensure that linked resources are included.
367+
368+ * Add Semigroup instances for everything for which we defined a
369+ Monoid instance previously (API change):
370+
371+ + Text.Pandoc.Class.FileTree.
372+ + Text.Pandoc.Translations.Translations.
373+ + Text.Pandoc.Extensions.Extensions.
374+ + Text.Pandoc.Readers.Odt.StyleReader.Styles.
375+ + Text.Pandoc.Pretty.Doc.
376+ + Text.Pandoc.MediaBag.MediaBag.
377+
378+ * Add custom Prelude to give clean code for Monoid and Semigroup
379+ that works with ghc 7.10-8.4. The custom Prelude (`prelude/Prelude`)
380+ is used for ghc versions < 8.4. `NoImplicitPrelude` is used
381+ in all source files, and Prelude is explicitly imported
382+ (this is necessary for ghci to work properly with the custom prelude).
383+
384+ * Text.Pandoc.Writers.Shared (Francesco Occhipinti):
385+
386+ + Export `stripLeadingTrailingSpace`.
387+ + Don't wrap lines in grid tables when `--wrap=none` (#4320).
388+ + `gridTable`: Don't wrap lines in tables when `--wrap=none`. Instead,
389+ expand cells, even if it results in cells that don't respect relative
390+ widths or surpass page column width. This change affects RST,
391+ Markdown, and Haddock writers.
392+
393+ * Raise error if someone tries to print docx, odt, etc. template (#4441).
394+
395+ * LaTeX template: Provide `bidi` package's option using
396+ `\PassOptionsToPackage` (#4357, Václav Haisman). This avoid a
397+ clash when `polyglossia` loads it first and then it is loaded again
398+ for XeLaTeX.
399+
400+ * ConTeXt template: Added `pdfa` variable to generate PDF/A (#4294, Henri
401+ Menke). Instructions on how to install the ICC profiles on ConTeXt
402+ standalone can be found in the wiki:
403+ <http://wiki.contextgarden.net/PDFX#ICC_profiles>.
404+ If the ICC profiles are not available the log will contain error
405+ messages.
406+
407+ * Use latest pandoc-types, skylighting
408+
409+ * Use latest pandoc-citeproc in binary package.
410+
411+ * Bump upper bound for time, criterion, haddock-library, exceptions,
412+ http-types, aeson, haddock-library.
413+
414+ * Bump upper bound tasty-quickcheck 0.10 (#4429, Felix Yan).
415+
416+ * pandoc.cabal: fix up other-extensions and language fields.
417+ Language is now consistently `Haskell2010`, and other-extensions
418+ is consistently `NoImplicitPrelude`. Everything else to be specified
419+ in the module header as needed.
420+
421+ * Removed `old-locale` flag and Text.Pandoc.Compat.Time.
422+ This is no longer necessary since we no longer support ghc 7.8.
423+
424+ * Make `weigh-pandoc` into a benchmark program.
425+ Remove `weigh-pandoc` flag. `weigh-pandoc` is now built (and run)
426+ automatically when you build (and run) benchmarks.
427+
428+ * MANUAL: add instructions for background images reveal.js (#4325, John
429+ Muccigrosso).
430+
431+ * appveyor: use VS 2013 environment instead of VS 2015 for Windows builds.
432+
433+
434+pandoc (2.1.2)
435+
436+ * Markdown reader:
437+
438+ + Fix parsing bug with nested fenced divs (#4281). Previously we allowed
439+ "nonindent spaces" before the opening and closing `:::`, but this
440+ interfered with list parsing, so now we require the fences to be flush with
441+ the margin of the containing block.
442+
443+ * Commonmark reader:
444+
445+ + `raw_html` is now on by default. It can be disabled explicitly
446+ using `-f commonmark-raw_html`.
447+
448+ * Org reader (Albert Krewinkel):
449+
450+ + Move citation tests to separate module.
451+ + Allow changing emphasis syntax (#4378). The characters allowed before
452+ and after emphasis can be configured via `#+pandoc-emphasis-pre` and
453+ `#+pandoc-emphasis-post`, respectively. This allows to change which
454+ strings are recognized as emphasized text on a per-document or even
455+ per-paragraph basis. Example:
456+
457+ #+pandoc-emphasis-pre: "-\t ('\"{"
458+ #+pandoc-emphasis-post: "-\t\n .,:!?;'\")}["
459+
460+ * LaTeX reader:
461+
462+ + Fixed comments inside citations (#4374).
463+ + Fix regression in package options including underscore (#4424).
464+ + Make `--trace` work.
465+ + Fixed parsing of `tabular*` environment (#4279).
466+
467+ * RST reader:
468+
469+ + Fix regression in parsing of headers with trailing space (#4280).
470+
471+ * Muse reader (Alexander Krotov):
472+
473+ + Enable `<literal>` tags even if amuse extension is enabled.
474+ Amusewiki disables <literal> tags for security reasons.
475+ If user wants similar behavior in pandoc, RawBlocks and RawInlines
476+ can be removed or replaced with filters.
477+ + Remove space prefix from `<literal>` tag contents.
478+ + Do not consume whitespace while looking for closing end tag.
479+ + Convert alphabetical list markers to decimal in round-trip test.
480+ Alphabetical lists are an addition of Text::Amuse.
481+ They are not present in Emacs Muse and can be ambiguous
482+ when list starts with "i.", "c." etc.
483+ + Allow `<quote>` and other tags to be indented.
484+ + Allow single colon in definition list term.
485+ + Fix parsing of verse in lists.
486+ + Improved parsing efficiency. Avoid `parseFromString`.
487+ Lists are parsed in linear instead of exponential time now.
488+ + Replace ParserState with MuseState.
489+ + Prioritize lists with roman numerals over alphabetical lists.
490+ This is to make sure "i." starts a roman numbered list,
491+ instead of a list with letter "i" (followed by "j", "k", ...").
492+ + Fix directive parsing.
493+ + Parse definition lists with multiple descriptions.
494+ + Parse next list item before parsing more item contents.
495+ + Fixed a bug: headers did not terminate lists.
496+ + Move indentation parsing from `definitionListItem` to `definitionList`.
497+ + Paragraph indentation does not indicate nested quote.
498+ Muse allows indentation to indicate quotation or alignment,
499+ but only on the top level, not within a <quote> or list.
500+ + Require that block tags are on separate lines.
501+ Text::Amuse already explicitly requires it anyway.
502+ + Fix matching of closing inline tags.
503+ + Various internal changes.
504+ + Fix parsing of nested definition lists.
505+ + Require only one space for nested definition list indentation.
506+ + Do not remove trailing whitespace from `<code>`.
507+ + Fix parsing of trailing whitespace. Newline after whitespace now
508+ results in softbreak instead of space.
509+
510+ * Docx reader (Jesse Rosenthal, except where noted):
511+
512+ + Handle nested sdt tags (#4415).
513+ + Don't look up dependant run styles if `+styles` is enabled.
514+ + Move pandoc inline styling inside custom-style span.
515+ + Read custom styles (#1843). This will read all paragraph and
516+ character classes as divs and spans, respectively. Dependent styles
517+ will still be resolved, but will be wrapped with appropriate style
518+ tags. It is controlled by the `+styles` extension (`-f docx+styles`).
519+ This can be used in conjunction with the `custom-style` feature in the
520+ docx writer for a pandoc-docx editing workflow. Users can convert from
521+ an input docx, reading the custom-styles, and then use that same input
522+ docx file as a reference-doc for producing an output docx file. Styles
523+ will be maintained across the conversion, even if pandoc doesn't
524+ understand them.
525+ + Small change to Fields hyperlink parser. Previously, unquoted string
526+ required a space at the end of the line (and consumed it). Now we
527+ either take a space (and don't consume it), or end of input.
528+ + Pick table width from the longest row or header (Francesco Occhipinti,
529+ #4360).
530+
531+ * Muse writer (Alexander Krotov):
532+
533+ + Change verse markup: `> ` instead of `<verse>` tag.
534+ + Remove empty strings during inline normalization.
535+ + Don't indent nested definition lists.
536+ + Use unicode quotes for quoted text.
537+ + Write image width specified in percent in Text::Amuse mode.
538+ + Don't wrap displayMath into `<verse>`.
539+ + Escape nonbreaking space (`~~`).
540+ + Join code with different attributes during normalization.
541+ + Indent lists inside Div.
542+ + Support definitions with multiple descriptions.
543+
544+ * Powerpoint writer (Jesse Rosenthal):
545+
546+ + Use table styles This will use the default table style in the
547+ reference-doc file. As a result they will be easier when using
548+ in a template, and match the color scheme.
549+ + Remove empty slides. Because of the way that slides were split, these
550+ could be accidentally produced by comments after images. When animations
551+ are added, there will be a way to add an empty slide with either
552+ incremental lists or pauses.
553+ + Implement syntax highlighting. Note that background colors can't
554+ be implemented in PowerPoint, so highlighting styles that require
555+ these will be incomplete.
556+ + New test framework for pptx. We now compare the output of the
557+ Powerpoint writer with files that we know to (a) not be corrupt,
558+ and (b) to show the desired output behavior (details below).
559+ + Add `notesMaster` to `presentation.xml` if necessary.
560+ + Ignore links and (end)notes in speaker notes.
561+ + Output speaker notes.
562+ + Read speaker note templates conditionally. If there are speaker
563+ notes in the presentation, we read in the notesMasters templates
564+ from the reference pptx file.
565+ + Fix deletion track changes (#4303, Jesse Rosenthal).
566+
567+ * Markdown writer: properly escape @ to avoid capture as citation
568+ (#4366).
569+
570+ * LaTeX writer:
571+
572+ + Put hypertarget inside figure environment (#4388).
573+ This works around a problem with the endfloat package and
574+ makes pandoc's output compatible with it.
575+ + Fix image height with percentage (#4389). This previously caused
576+ the image to be resized to a percentage of textwidth, rather than
577+ textheight.
578+
579+ * ConTeXt writer (Henri Menke):
580+
581+ + New section syntax and support `--section-divs` (#2609).
582+ `\section[my-header]{My Header}` ->
583+ `\section[title={My Header},reference={my-header}]`.
584+ The ConTeXt writer now supports the `--section-divs` option to
585+ write sections in the fenced style, with `\startsection` and
586+ `\stopsection`.
587+ + xtables: correct wrong usage of caption (Henri Menke).
588+
589+ * Docx writer:
590+
591+ + Fix image resizing with multiple images (#3930, Andrew Pritchard).
592+ + Use new golden framework (Jesse Rosenthal).
593+ + Make more deterministic to facilitate testing (Jesse Rosenthal).
594+ - `getUniqueId` now calls to the state to get an incremented digit,
595+ instead of calling to P.uniqueHash.
596+ - we always start the PRNG in mkNumbering/mkAbstractNum with the same
597+ seed (1848), so our randoms should be the same each time.
598+ + Fix ids in comment writing (Jesse Rosenthal). Comments from
599+ `--track-changes=all` were producing corrupt docx, because the
600+ writer was trying to get id from the `(ID,_,_)` field of
601+ the attributes, and ignoring the "id" entry in the key-value pairs. We
602+ now check both.
603+
604+ * Ms writer: Added papersize variable.
605+
606+ * TEI writer:
607+
608+ + Use `height` instead of `depth` for images (#4331).
609+ + Ensure that id prefix is always used.
610+ + Don't emit `role` attribute; that was a leftover from the
611+ Docbook writer.
612+ + Use 'xml:id', not 'id' attribute (#4371).
613+
614+ * AsciiDoc writer:
615+
616+ + Do not output implicit heading IDs (#4363, Alexander
617+ Krotov). Convert to `asciidoc-auto_identifiers` for old behaviour.
618+
619+ * RST writer:
620+
621+ + Remove `blockToRST'` moving its logic into `fixBlocks`
622+ (Francesco Occhipinti).
623+ + Insert comment between lists and quotes (#4248, Francesco Occchipinti).
624+
625+ * RST template: remove definition of 'math' role as raw.
626+ This used to be needed prior to v 0.8 of docutils, but
627+ now math support is built-in.
628+
629+ * Slides: Use divs to set incremental/non-incremental (#4381,
630+ Jesse Rosenthal). The old method (list inside blockquote) still
631+ works, but we are encouraging the use of divs with class
632+ `incremental` or `nonincremental`.
633+
634+ * Text.Pandoc.ImageSize:
635+
636+ + Make image size detection for PDFs more robust (#4322).
637+ + Determine image size for PDFs (#4322).
638+ + EMF Image size support (#4375, Andrew Pritchard).
639+
640+ * Text.Pandoc.Extensions:
641+
642+ + Add `Ext_styles` (Jesse Rosenthal, API change). This will be used in
643+ the docx reader (defaulting to off) to read pargraph and character
644+ styles not understood by pandoc (as divs and spans, respectively).
645+ + Made `Ext_raw_html` default for `commonmark` format.
646+
647+ * Text.Pandoc.Parsing:
648+
649+ + Export `manyUntil` (Alexander Krotov, API change).
650+ + Export improved `sepBy1` (Alexander Krotov).
651+ + Export list marker parsers: `upperRoman`, `lowerRoman`,
652+ `decimal`, `lowerAlpha`, `upperAlpha` (Alexander Krotov, API change).
653+
654+ * Tests/Lua: fix tests on windows (Albert Krewinkel).
655+
656+ * Lua: register script name in global variable (#4393). The name of the Lua
657+ script which is executed is made available in the global Lua variable
658+ `PANDOC_SCRIPT_FILE`, both for Lua filters and custom writers.
659+
660+ * Tests: Abstract powerpoint tests out to OOXML tests (Jesse Rosenthal).
661+ There is very little pptx-specific in these tests, so we abstract out
662+ the basic testing function so it can be used for docx as well. This
663+ should allow us to catch some errors in the docx writer that slipped
664+ by the roundtrip testing.
665+
666+ * Lua filters: store constructors in registry (Albert Krewinkel). Lua
667+ functions used to construct AST element values are stored in the Lua
668+ registry for quicker access. Getting a value from the registry is much
669+ faster than getting a global value (partly to idiosyncrasies of hslua);
670+ this change results in a considerable performance boost.
671+
672+ * Documentation:
673+
674+ + `doc/org.md` Add draft of Org-mode documentation (Albert Krewinkel).
675+ + `doc/lua-filters.md`: document global vars set for filters
676+ (Albert Krewinkel).
677+ + INSTALL.md: mention Stack version. (#4343, Adam Brandizzi).
678+ + MANUAL: add documentation on custom styles (Jesse Rosenthal).
679+ + MANUAL.txt: Document incremental and nonincremental divs (Jesse
680+ Rosenthal). Blockquoted lists are still described, but fenced divs are
681+ presented in preference.
682+ + MANUAL.txt: document header and footer variables (newmana).
683+ + MANUAL.txt: self-contained implies standalone (#4304, Daniel Lublin).
684+ + CONTRIBUTING.md: label was renamed. (#4310, Alexander Brandizzi).
685+
686+ * Require tagsoup 0.14.3 (#4282), fixing HTML tokenization bug.
687+
688+ * Use latest texmath.
689+
690+ * Use latest pandoc-citeproc.
691+
692+ * Allow exceptions 0.9.
693+
694+ * Require aeson-pretty 0.8.5 (#4394).
695+
696+ * Bump blaze-markup, blaze-html lower bounds to 0.8, 0.9 (#4334).
697+
698+ * Update tagsoup to 0.14.6 (Alexander Krotov, #4282).
699+
700+ * Removed ghc-prof-options. As of cabal 1.24, sensible defaults are used.
701+
702+ * Update default.nix to current nixpkgs-unstable for hslua-0.9.5 (#4348,
703+ jarlg).
704+
705+
1706pandoc (2.1.1)
2707
3708 * Markdown reader:
@@ -1299,7 +2004,7 @@ pandoc (2.0)
12992004 directory. However, the working directory must be explicitly
13002005 specified if the `--resource-path` option is used.
13012006
1302− * Added --abbreviations=FILE option for custom abbreviations file
2007+ * Added `--abbreviations=FILE` option for custom abbreviations file
13032008 (#256). Default abbreviations file (`data/abbreviations`) contains
13042009 a list of strings that will be recognized by pandoc's
13052010 Markdown parser as abbreviations. (A nonbreaking space will
@@ -1704,7 +2409,7 @@ pandoc (2.0)
17042409 * HTML reader: parse a span with class `smallcaps` as `SmallCaps`.
17052410
17062411 * LaTeX reader:
1707−
2412+
17082413 + Implemented `\graphicspath` (#736).
17092414 + Properly handle column prefixes/suffixes. For example, in
17102415 `\begin{tabular}{>{$}l<{$}>{$}l<{$} >{$}l<{$}}`
data/LaTeXMathML.jsdeleted−198
@@ -1,198 +0,0 @@
1−/*
2−LaTeXMathML.js from http://math.etsu.edu/LaTeXMathML/
3−Adapted by Jeff Knisely and Douglas Woodall from ASCIIMathML.js v. 1.4.7,
4−(c) 2005 Peter Jipsen http://www.chapman.edu/~jipsen.
5−Released under the GNU General Public License version 2 or later.
6−See the GNU General Public License (at http://www.gnu.org/copyleft/gpl.html)
7−for more details.
8−*/
9−var checkForMathML=true;var notifyIfNoMathML=true;var alertIfNoMathML=false;var mathcolor="";var mathfontfamily="";var showasciiformulaonhover=true;var isIE=document.createElementNS==null;if(document.getElementById==null)
10−alert("This webpage requires a recent browser such as \nMozilla/Netscape 7+ or Internet Explorer 6+MathPlayer")
11−function AMcreateElementXHTML(t){if(isIE)return document.createElement(t);else return document.createElementNS("http://www.w3.org/1999/xhtml",t);}
12−function AMnoMathMLNote(){var nd=AMcreateElementXHTML("h3");nd.setAttribute("align","center")
13−nd.appendChild(AMcreateElementXHTML("p"));nd.appendChild(document.createTextNode("To view the "));var an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("LaTeXMathML"));an.setAttribute("href","http://www.maths.nott.ac.uk/personal/drw/lm.html");nd.appendChild(an);nd.appendChild(document.createTextNode(" notation use Internet Explorer 6+"));an=AMcreateElementXHTML("a");an.appendChild(document.createTextNode("MathPlayer"));an.setAttribute("href","http://www.dessci.com/en/products/mathplayer/download.htm");nd.appendChild(an);nd.appendChild(document.createTextNode(" or Netscape/Mozilla/Firefox"));nd.appendChild(AMcreateElementXHTML("p"));return nd;}
14−function AMisMathMLavailable(){if(navigator.appName.slice(0,8)=="Netscape")
15−if(navigator.appVersion.slice(0,1)>="5")return null;else return AMnoMathMLNote();else if(navigator.appName.slice(0,9)=="Microsoft")
16−try{var ActiveX=new ActiveXObject("MathPlayer.Factory.1");return null;}catch(e){return AMnoMathMLNote();}
17−else return AMnoMathMLNote();}
18−var AMcal=[0xEF35,0x212C,0xEF36,0xEF37,0x2130,0x2131,0xEF38,0x210B,0x2110,0xEF39,0xEF3A,0x2112,0x2133,0xEF3B,0xEF3C,0xEF3D,0xEF3E,0x211B,0xEF3F,0xEF40,0xEF41,0xEF42,0xEF43,0xEF44,0xEF45,0xEF46];var AMfrk=[0xEF5D,0xEF5E,0x212D,0xEF5F,0xEF60,0xEF61,0xEF62,0x210C,0x2111,0xEF63,0xEF64,0xEF65,0xEF66,0xEF67,0xEF68,0xEF69,0xEF6A,0x211C,0xEF6B,0xEF6C,0xEF6D,0xEF6E,0xEF6F,0xEF70,0xEF71,0x2128];var AMbbb=[0xEF8C,0xEF8D,0x2102,0xEF8E,0xEF8F,0xEF90,0xEF91,0x210D,0xEF92,0xEF93,0xEF94,0xEF95,0xEF96,0x2115,0xEF97,0x2119,0x211A,0x211D,0xEF98,0xEF99,0xEF9A,0xEF9B,0xEF9C,0xEF9D,0xEF9E,0x2124];var CONST=0,UNARY=1,BINARY=2,INFIX=3,LEFTBRACKET=4,RIGHTBRACKET=5,SPACE=6,UNDEROVER=7,DEFINITION=8,TEXT=9,BIG=10,LONG=11,STRETCHY=12,MATRIX=13;var AMsqrt={input:"\\sqrt",tag:"msqrt",output:"sqrt",ttype:UNARY},AMroot={input:"\\root",tag:"mroot",output:"root",ttype:BINARY},AMfrac={input:"\\frac",tag:"mfrac",output:"/",ttype:BINARY},AMover={input:"\\stackrel",tag:"mover",output:"stackrel",ttype:BINARY},AMatop={input:"\\atop",tag:"mfrac",output:"",ttype:INFIX},AMchoose={input:"\\choose",tag:"mfrac",output:"",ttype:INFIX},AMsub={input:"_",tag:"msub",output:"_",ttype:INFIX},AMsup={input:"^",tag:"msup",output:"^",ttype:INFIX},AMtext={input:"\\mathrm",tag:"mtext",output:"text",ttype:TEXT},AMmbox={input:"\\mbox",tag:"mtext",output:"mbox",ttype:TEXT};var AMsymbols=[{input:"\\alpha",tag:"mi",output:"\u03B1",ttype:CONST},{input:"\\beta",tag:"mi",output:"\u03B2",ttype:CONST},{input:"\\gamma",tag:"mi",output:"\u03B3",ttype:CONST},{input:"\\delta",tag:"mi",output:"\u03B4",ttype:CONST},{input:"\\epsilon",tag:"mi",output:"\u03B5",ttype:CONST},{input:"\\varepsilon",tag:"mi",output:"\u025B",ttype:CONST},{input:"\\zeta",tag:"mi",output:"\u03B6",ttype:CONST},{input:"\\eta",tag:"mi",output:"\u03B7",ttype:CONST},{input:"\\theta",tag:"mi",output:"\u03B8",ttype:CONST},{input:"\\vartheta",tag:"mi",output:"\u03D1",ttype:CONST},{input:"\\iota",tag:"mi",output:"\u03B9",ttype:CONST},{input:"\\kappa",tag:"mi",output:"\u03BA",ttype:CONST},{input:"\\lambda",tag:"mi",output:"\u03BB",ttype:CONST},{input:"\\mu",tag:"mi",output:"\u03BC",ttype:CONST},{input:"\\nu",tag:"mi",output:"\u03BD",ttype:CONST},{input:"\\xi",tag:"mi",output:"\u03BE",ttype:CONST},{input:"\\pi",tag:"mi",output:"\u03C0",ttype:CONST},{input:"\\varpi",tag:"mi",output:"\u03D6",ttype:CONST},{input:"\\rho",tag:"mi",output:"\u03C1",ttype:CONST},{input:"\\varrho",tag:"mi",output:"\u03F1",ttype:CONST},{input:"\\varsigma",tag:"mi",output:"\u03C2",ttype:CONST},{input:"\\sigma",tag:"mi",output:"\u03C3",ttype:CONST},{input:"\\tau",tag:"mi",output:"\u03C4",ttype:CONST},{input:"\\upsilon",tag:"mi",output:"\u03C5",ttype:CONST},{input:"\\phi",tag:"mi",output:"\u03C6",ttype:CONST},{input:"\\varphi",tag:"mi",output:"\u03D5",ttype:CONST},{input:"\\chi",tag:"mi",output:"\u03C7",ttype:CONST},{input:"\\psi",tag:"mi",output:"\u03C8",ttype:CONST},{input:"\\omega",tag:"mi",output:"\u03C9",ttype:CONST},{input:"\\Gamma",tag:"mo",output:"\u0393",ttype:CONST},{input:"\\Delta",tag:"mo",output:"\u0394",ttype:CONST},{input:"\\Theta",tag:"mo",output:"\u0398",ttype:CONST},{input:"\\Lambda",tag:"mo",output:"\u039B",ttype:CONST},{input:"\\Xi",tag:"mo",output:"\u039E",ttype:CONST},{input:"\\Pi",tag:"mo",output:"\u03A0",ttype:CONST},{input:"\\Sigma",tag:"mo",output:"\u03A3",ttype:CONST},{input:"\\Upsilon",tag:"mo",output:"\u03A5",ttype:CONST},{input:"\\Phi",tag:"mo",output:"\u03A6",ttype:CONST},{input:"\\Psi",tag:"mo",output:"\u03A8",ttype:CONST},{input:"\\Omega",tag:"mo",output:"\u03A9",ttype:CONST},{input:"\\frac12",tag:"mo",output:"\u00BD",ttype:CONST},{input:"\\frac14",tag:"mo",output:"\u00BC",ttype:CONST},{input:"\\frac34",tag:"mo",output:"\u00BE",ttype:CONST},{input:"\\frac13",tag:"mo",output:"\u2153",ttype:CONST},{input:"\\frac23",tag:"mo",output:"\u2154",ttype:CONST},{input:"\\frac15",tag:"mo",output:"\u2155",ttype:CONST},{input:"\\frac25",tag:"mo",output:"\u2156",ttype:CONST},{input:"\\frac35",tag:"mo",output:"\u2157",ttype:CONST},{input:"\\frac45",tag:"mo",output:"\u2158",ttype:CONST},{input:"\\frac16",tag:"mo",output:"\u2159",ttype:CONST},{input:"\\frac56",tag:"mo",output:"\u215A",ttype:CONST},{input:"\\frac18",tag:"mo",output:"\u215B",ttype:CONST},{input:"\\frac38",tag:"mo",output:"\u215C",ttype:CONST},{input:"\\frac58",tag:"mo",output:"\u215D",ttype:CONST},{input:"\\frac78",tag:"mo",output:"\u215E",ttype:CONST},{input:"\\pm",tag:"mo",output:"\u00B1",ttype:CONST},{input:"\\mp",tag:"mo",output:"\u2213",ttype:CONST},{input:"\\triangleleft",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\triangleright",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\cdot",tag:"mo",output:"\u22C5",ttype:CONST},{input:"\\star",tag:"mo",output:"\u22C6",ttype:CONST},{input:"\\ast",tag:"mo",output:"\u002A",ttype:CONST},{input:"\\times",tag:"mo",output:"\u00D7",ttype:CONST},{input:"\\div",tag:"mo",output:"\u00F7",ttype:CONST},{input:"\\circ",tag:"mo",output:"\u2218",ttype:CONST},{input:"\\bullet",tag:"mo",output:"\u2022",ttype:CONST},{input:"\\oplus",tag:"mo",output:"\u2295",ttype:CONST},{input:"\\ominus",tag:"mo",output:"\u2296",ttype:CONST},{input:"\\otimes",tag:"mo",output:"\u2297",ttype:CONST},{input:"\\bigcirc",tag:"mo",output:"\u25CB",ttype:CONST},{input:"\\oslash",tag:"mo",output:"\u2298",ttype:CONST},{input:"\\odot",tag:"mo",output:"\u2299",ttype:CONST},{input:"\\land",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\wedge",tag:"mo",output:"\u2227",ttype:CONST},{input:"\\lor",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\vee",tag:"mo",output:"\u2228",ttype:CONST},{input:"\\cap",tag:"mo",output:"\u2229",ttype:CONST},{input:"\\cup",tag:"mo",output:"\u222A",ttype:CONST},{input:"\\sqcap",tag:"mo",output:"\u2293",ttype:CONST},{input:"\\sqcup",tag:"mo",output:"\u2294",ttype:CONST},{input:"\\uplus",tag:"mo",output:"\u228E",ttype:CONST},{input:"\\amalg",tag:"mo",output:"\u2210",ttype:CONST},{input:"\\bigtriangleup",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\bigtriangledown",tag:"mo",output:"\u25BD",ttype:CONST},{input:"\\dag",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\dagger",tag:"mo",output:"\u2020",ttype:CONST},{input:"\\ddag",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\ddagger",tag:"mo",output:"\u2021",ttype:CONST},{input:"\\lhd",tag:"mo",output:"\u22B2",ttype:CONST},{input:"\\rhd",tag:"mo",output:"\u22B3",ttype:CONST},{input:"\\unlhd",tag:"mo",output:"\u22B4",ttype:CONST},{input:"\\unrhd",tag:"mo",output:"\u22B5",ttype:CONST},{input:"\\sum",tag:"mo",output:"\u2211",ttype:UNDEROVER},{input:"\\prod",tag:"mo",output:"\u220F",ttype:UNDEROVER},{input:"\\bigcap",tag:"mo",output:"\u22C2",ttype:UNDEROVER},{input:"\\bigcup",tag:"mo",output:"\u22C3",ttype:UNDEROVER},{input:"\\bigwedge",tag:"mo",output:"\u22C0",ttype:UNDEROVER},{input:"\\bigvee",tag:"mo",output:"\u22C1",ttype:UNDEROVER},{input:"\\bigsqcap",tag:"mo",output:"\u2A05",ttype:UNDEROVER},{input:"\\bigsqcup",tag:"mo",output:"\u2A06",ttype:UNDEROVER},{input:"\\coprod",tag:"mo",output:"\u2210",ttype:UNDEROVER},{input:"\\bigoplus",tag:"mo",output:"\u2A01",ttype:UNDEROVER},{input:"\\bigotimes",tag:"mo",output:"\u2A02",ttype:UNDEROVER},{input:"\\bigodot",tag:"mo",output:"\u2A00",ttype:UNDEROVER},{input:"\\biguplus",tag:"mo",output:"\u2A04",ttype:UNDEROVER},{input:"\\int",tag:"mo",output:"\u222B",ttype:CONST},{input:"\\oint",tag:"mo",output:"\u222E",ttype:CONST},{input:":=",tag:"mo",output:":=",ttype:CONST},{input:"\\lt",tag:"mo",output:"<",ttype:CONST},{input:"\\gt",tag:"mo",output:">",ttype:CONST},{input:"\\ne",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\neq",tag:"mo",output:"\u2260",ttype:CONST},{input:"\\le",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leq",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\leqslant",tag:"mo",output:"\u2264",ttype:CONST},{input:"\\ge",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geq",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\geqslant",tag:"mo",output:"\u2265",ttype:CONST},{input:"\\equiv",tag:"mo",output:"\u2261",ttype:CONST},{input:"\\ll",tag:"mo",output:"\u226A",ttype:CONST},{input:"\\gg",tag:"mo",output:"\u226B",ttype:CONST},{input:"\\doteq",tag:"mo",output:"\u2250",ttype:CONST},{input:"\\prec",tag:"mo",output:"\u227A",ttype:CONST},{input:"\\succ",tag:"mo",output:"\u227B",ttype:CONST},{input:"\\preceq",tag:"mo",output:"\u227C",ttype:CONST},{input:"\\succeq",tag:"mo",output:"\u227D",ttype:CONST},{input:"\\subset",tag:"mo",output:"\u2282",ttype:CONST},{input:"\\supset",tag:"mo",output:"\u2283",ttype:CONST},{input:"\\subseteq",tag:"mo",output:"\u2286",ttype:CONST},{input:"\\supseteq",tag:"mo",output:"\u2287",ttype:CONST},{input:"\\sqsubset",tag:"mo",output:"\u228F",ttype:CONST},{input:"\\sqsupset",tag:"mo",output:"\u2290",ttype:CONST},{input:"\\sqsubseteq",tag:"mo",output:"\u2291",ttype:CONST},{input:"\\sqsupseteq",tag:"mo",output:"\u2292",ttype:CONST},{input:"\\sim",tag:"mo",output:"\u223C",ttype:CONST},{input:"\\simeq",tag:"mo",output:"\u2243",ttype:CONST},{input:"\\approx",tag:"mo",output:"\u2248",ttype:CONST},{input:"\\cong",tag:"mo",output:"\u2245",ttype:CONST},{input:"\\Join",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\bowtie",tag:"mo",output:"\u22C8",ttype:CONST},{input:"\\in",tag:"mo",output:"\u2208",ttype:CONST},{input:"\\ni",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\owns",tag:"mo",output:"\u220B",ttype:CONST},{input:"\\propto",tag:"mo",output:"\u221D",ttype:CONST},{input:"\\vdash",tag:"mo",output:"\u22A2",ttype:CONST},{input:"\\dashv",tag:"mo",output:"\u22A3",ttype:CONST},{input:"\\models",tag:"mo",output:"\u22A8",ttype:CONST},{input:"\\perp",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\smile",tag:"mo",output:"\u2323",ttype:CONST},{input:"\\frown",tag:"mo",output:"\u2322",ttype:CONST},{input:"\\asymp",tag:"mo",output:"\u224D",ttype:CONST},{input:"\\notin",tag:"mo",output:"\u2209",ttype:CONST},{input:"\\begin{eqnarray}",output:"X",ttype:MATRIX,invisible:true},{input:"\\begin{array}",output:"X",ttype:MATRIX,invisible:true},{input:"\\\\",output:"}&{",ttype:DEFINITION},{input:"\\end{eqnarray}",output:"}}",ttype:DEFINITION},{input:"\\end{array}",output:"}}",ttype:DEFINITION},{input:"\\big",tag:"mo",output:"X",atval:"1.2",ieval:"2.2",ttype:BIG},{input:"\\Big",tag:"mo",output:"X",atval:"1.6",ieval:"2.6",ttype:BIG},{input:"\\bigg",tag:"mo",output:"X",atval:"2.2",ieval:"3.2",ttype:BIG},{input:"\\Bigg",tag:"mo",output:"X",atval:"2.9",ieval:"3.9",ttype:BIG},{input:"\\left",tag:"mo",output:"X",ttype:LEFTBRACKET},{input:"\\right",tag:"mo",output:"X",ttype:RIGHTBRACKET},{input:"{",output:"{",ttype:LEFTBRACKET,invisible:true},{input:"}",output:"}",ttype:RIGHTBRACKET,invisible:true},{input:"(",tag:"mo",output:"(",atval:"1",ttype:STRETCHY},{input:"[",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\lbrack",tag:"mo",output:"[",atval:"1",ttype:STRETCHY},{input:"\\{",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\lbrace",tag:"mo",output:"{",atval:"1",ttype:STRETCHY},{input:"\\langle",tag:"mo",output:"\u2329",atval:"1",ttype:STRETCHY},{input:"\\lfloor",tag:"mo",output:"\u230A",atval:"1",ttype:STRETCHY},{input:"\\lceil",tag:"mo",output:"\u2308",atval:"1",ttype:STRETCHY},{input:")",tag:"mo",output:")",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"]",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrack",tag:"mo",output:"]",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\}",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rbrace",tag:"mo",output:"}",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rangle",tag:"mo",output:"\u232A",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rfloor",tag:"mo",output:"\u230B",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"\\rceil",tag:"mo",output:"\u2309",rtag:"mi",atval:"1",ttype:STRETCHY},{input:"|",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\|",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\vert",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\Vert",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"\\mid",tag:"mo",output:"\u2223",atval:"1",ttype:STRETCHY},{input:"\\parallel",tag:"mo",output:"\u2225",atval:"1",ttype:STRETCHY},{input:"/",tag:"mo",output:"/",atval:"1.01",ttype:STRETCHY},{input:"\\backslash",tag:"mo",output:"\u2216",atval:"1",ttype:STRETCHY},{input:"\\setminus",tag:"mo",output:"\\",ttype:CONST},{input:"\\!",tag:"mspace",atname:"width",atval:"-0.167em",ttype:SPACE},{input:"\\,",tag:"mspace",atname:"width",atval:"0.167em",ttype:SPACE},{input:"\\>",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\:",tag:"mspace",atname:"width",atval:"0.222em",ttype:SPACE},{input:"\\;",tag:"mspace",atname:"width",atval:"0.278em",ttype:SPACE},{input:"~",tag:"mspace",atname:"width",atval:"0.333em",ttype:SPACE},{input:"\\quad",tag:"mspace",atname:"width",atval:"1em",ttype:SPACE},{input:"\\qquad",tag:"mspace",atname:"width",atval:"2em",ttype:SPACE},{input:"\\prime",tag:"mo",output:"\u2032",ttype:CONST},{input:"'",tag:"mo",output:"\u02B9",ttype:CONST},{input:"''",tag:"mo",output:"\u02BA",ttype:CONST},{input:"'''",tag:"mo",output:"\u2034",ttype:CONST},{input:"''''",tag:"mo",output:"\u2057",ttype:CONST},{input:"\\ldots",tag:"mo",output:"\u2026",ttype:CONST},{input:"\\cdots",tag:"mo",output:"\u22EF",ttype:CONST},{input:"\\vdots",tag:"mo",output:"\u22EE",ttype:CONST},{input:"\\ddots",tag:"mo",output:"\u22F1",ttype:CONST},{input:"\\forall",tag:"mo",output:"\u2200",ttype:CONST},{input:"\\exists",tag:"mo",output:"\u2203",ttype:CONST},{input:"\\Re",tag:"mo",output:"\u211C",ttype:CONST},{input:"\\Im",tag:"mo",output:"\u2111",ttype:CONST},{input:"\\aleph",tag:"mo",output:"\u2135",ttype:CONST},{input:"\\hbar",tag:"mo",output:"\u210F",ttype:CONST},{input:"\\ell",tag:"mo",output:"\u2113",ttype:CONST},{input:"\\wp",tag:"mo",output:"\u2118",ttype:CONST},{input:"\\emptyset",tag:"mo",output:"\u2205",ttype:CONST},{input:"\\infty",tag:"mo",output:"\u221E",ttype:CONST},{input:"\\surd",tag:"mo",output:"\\sqrt{}",ttype:DEFINITION},{input:"\\partial",tag:"mo",output:"\u2202",ttype:CONST},{input:"\\nabla",tag:"mo",output:"\u2207",ttype:CONST},{input:"\\triangle",tag:"mo",output:"\u25B3",ttype:CONST},{input:"\\therefore",tag:"mo",output:"\u2234",ttype:CONST},{input:"\\angle",tag:"mo",output:"\u2220",ttype:CONST},{input:"\\diamond",tag:"mo",output:"\u22C4",ttype:CONST},{input:"\\Diamond",tag:"mo",output:"\u25C7",ttype:CONST},{input:"\\neg",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\lnot",tag:"mo",output:"\u00AC",ttype:CONST},{input:"\\bot",tag:"mo",output:"\u22A5",ttype:CONST},{input:"\\top",tag:"mo",output:"\u22A4",ttype:CONST},{input:"\\square",tag:"mo",output:"\u25AB",ttype:CONST},{input:"\\Box",tag:"mo",output:"\u25A1",ttype:CONST},{input:"\\wr",tag:"mo",output:"\u2240",ttype:CONST},{input:"\\arccos",tag:"mi",output:"arccos",ttype:UNARY,func:true},{input:"\\arcsin",tag:"mi",output:"arcsin",ttype:UNARY,func:true},{input:"\\arctan",tag:"mi",output:"arctan",ttype:UNARY,func:true},{input:"\\arg",tag:"mi",output:"arg",ttype:UNARY,func:true},{input:"\\cos",tag:"mi",output:"cos",ttype:UNARY,func:true},{input:"\\cosh",tag:"mi",output:"cosh",ttype:UNARY,func:true},{input:"\\cot",tag:"mi",output:"cot",ttype:UNARY,func:true},{input:"\\coth",tag:"mi",output:"coth",ttype:UNARY,func:true},{input:"\\csc",tag:"mi",output:"csc",ttype:UNARY,func:true},{input:"\\deg",tag:"mi",output:"deg",ttype:UNARY,func:true},{input:"\\det",tag:"mi",output:"det",ttype:UNARY,func:true},{input:"\\dim",tag:"mi",output:"dim",ttype:UNARY,func:true},{input:"\\exp",tag:"mi",output:"exp",ttype:UNARY,func:true},{input:"\\gcd",tag:"mi",output:"gcd",ttype:UNARY,func:true},{input:"\\hom",tag:"mi",output:"hom",ttype:UNARY,func:true},{input:"\\inf",tag:"mo",output:"inf",ttype:UNDEROVER},{input:"\\ker",tag:"mi",output:"ker",ttype:UNARY,func:true},{input:"\\lg",tag:"mi",output:"lg",ttype:UNARY,func:true},{input:"\\lim",tag:"mo",output:"lim",ttype:UNDEROVER},{input:"\\liminf",tag:"mo",output:"liminf",ttype:UNDEROVER},{input:"\\limsup",tag:"mo",output:"limsup",ttype:UNDEROVER},{input:"\\ln",tag:"mi",output:"ln",ttype:UNARY,func:true},{input:"\\log",tag:"mi",output:"log",ttype:UNARY,func:true},{input:"\\max",tag:"mo",output:"max",ttype:UNDEROVER},{input:"\\min",tag:"mo",output:"min",ttype:UNDEROVER},{input:"\\Pr",tag:"mi",output:"Pr",ttype:UNARY,func:true},{input:"\\sec",tag:"mi",output:"sec",ttype:UNARY,func:true},{input:"\\sin",tag:"mi",output:"sin",ttype:UNARY,func:true},{input:"\\sinh",tag:"mi",output:"sinh",ttype:UNARY,func:true},{input:"\\sup",tag:"mo",output:"sup",ttype:UNDEROVER},{input:"\\tan",tag:"mi",output:"tan",ttype:UNARY,func:true},{input:"\\tanh",tag:"mi",output:"tanh",ttype:UNARY,func:true},{input:"\\gets",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\leftarrow",tag:"mo",output:"\u2190",ttype:CONST},{input:"\\to",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\rightarrow",tag:"mo",output:"\u2192",ttype:CONST},{input:"\\leftrightarrow",tag:"mo",output:"\u2194",ttype:CONST},{input:"\\uparrow",tag:"mo",output:"\u2191",ttype:CONST},{input:"\\downarrow",tag:"mo",output:"\u2193",ttype:CONST},{input:"\\updownarrow",tag:"mo",output:"\u2195",ttype:CONST},{input:"\\Leftarrow",tag:"mo",output:"\u21D0",ttype:CONST},{input:"\\Rightarrow",tag:"mo",output:"\u21D2",ttype:CONST},{input:"\\Leftrightarrow",tag:"mo",output:"\u21D4",ttype:CONST},{input:"\\iff",tag:"mo",output:"~\\Longleftrightarrow~",ttype:DEFINITION},{input:"\\Uparrow",tag:"mo",output:"\u21D1",ttype:CONST},{input:"\\Downarrow",tag:"mo",output:"\u21D3",ttype:CONST},{input:"\\Updownarrow",tag:"mo",output:"\u21D5",ttype:CONST},{input:"\\mapsto",tag:"mo",output:"\u21A6",ttype:CONST},{input:"\\longleftarrow",tag:"mo",output:"\u2190",ttype:LONG},{input:"\\longrightarrow",tag:"mo",output:"\u2192",ttype:LONG},{input:"\\longleftrightarrow",tag:"mo",output:"\u2194",ttype:LONG},{input:"\\Longleftarrow",tag:"mo",output:"\u21D0",ttype:LONG},{input:"\\Longrightarrow",tag:"mo",output:"\u21D2",ttype:LONG},{input:"\\Longleftrightarrow",tag:"mo",output:"\u21D4",ttype:LONG},{input:"\\longmapsto",tag:"mo",output:"\u21A6",ttype:CONST},AMsqrt,AMroot,AMfrac,AMover,AMsub,AMsup,AMtext,AMmbox,AMatop,AMchoose,{input:"\\acute",tag:"mover",output:"\u00B4",ttype:UNARY,acc:true},{input:"\\grave",tag:"mover",output:"\u0060",ttype:UNARY,acc:true},{input:"\\breve",tag:"mover",output:"\u02D8",ttype:UNARY,acc:true},{input:"\\check",tag:"mover",output:"\u02C7",ttype:UNARY,acc:true},{input:"\\dot",tag:"mover",output:".",ttype:UNARY,acc:true},{input:"\\ddot",tag:"mover",output:"..",ttype:UNARY,acc:true},{input:"\\mathring",tag:"mover",output:"\u00B0",ttype:UNARY,acc:true},{input:"\\vec",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overrightarrow",tag:"mover",output:"\u20D7",ttype:UNARY,acc:true},{input:"\\overleftarrow",tag:"mover",output:"\u20D6",ttype:UNARY,acc:true},{input:"\\hat",tag:"mover",output:"\u005E",ttype:UNARY,acc:true},{input:"\\widehat",tag:"mover",output:"\u0302",ttype:UNARY,acc:true},{input:"\\tilde",tag:"mover",output:"~",ttype:UNARY,acc:true},{input:"\\widetilde",tag:"mover",output:"\u02DC",ttype:UNARY,acc:true},{input:"\\bar",tag:"mover",output:"\u203E",ttype:UNARY,acc:true},{input:"\\overbrace",tag:"mover",output:"\uFE37",ttype:UNARY,acc:true},{input:"\\overbracket",tag:"mover",output:"\u23B4",ttype:UNARY,acc:true},{input:"\\overline",tag:"mover",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\underbrace",tag:"munder",output:"\uFE38",ttype:UNARY,acc:true},{input:"\\underbracket",tag:"munder",output:"\u23B5",ttype:UNARY,acc:true},{input:"\\underline",tag:"munder",output:"\u00AF",ttype:UNARY,acc:true},{input:"\\displaystyle",tag:"mstyle",atname:"displaystyle",atval:"true",ttype:UNARY},{input:"\\textstyle",tag:"mstyle",atname:"displaystyle",atval:"false",ttype:UNARY},{input:"\\scriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"1",ttype:UNARY},{input:"\\scriptscriptstyle",tag:"mstyle",atname:"scriptlevel",atval:"2",ttype:UNARY},{input:"\\textrm",tag:"mstyle",output:"\\mathrm",ttype:DEFINITION},{input:"\\mathbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\textbf",tag:"mstyle",atname:"mathvariant",atval:"bold",ttype:UNARY},{input:"\\mathit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\textit",tag:"mstyle",atname:"mathvariant",atval:"italic",ttype:UNARY},{input:"\\mathtt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\texttt",tag:"mstyle",atname:"mathvariant",atval:"monospace",ttype:UNARY},{input:"\\mathsf",tag:"mstyle",atname:"mathvariant",atval:"sans-serif",ttype:UNARY},{input:"\\mathbb",tag:"mstyle",atname:"mathvariant",atval:"double-struck",ttype:UNARY,codes:AMbbb},{input:"\\mathcal",tag:"mstyle",atname:"mathvariant",atval:"script",ttype:UNARY,codes:AMcal},{input:"\\mathfrak",tag:"mstyle",atname:"mathvariant",atval:"fraktur",ttype:UNARY,codes:AMfrk},{input:"\\textcolor",tag:"mstyle",atname:"mathvariant",atval:"mathcolor",ttype:BINARY},{input:"\\colorbox",tag:"mstyle",atname:"mathvariant",atval:"background",ttype:BINARY}];function compareNames(s1,s2){if(s1.input>s2.input)return 1
19−else return-1;}
20−var AMnames=[];function AMinitSymbols(){AMsymbols.sort(compareNames);for(i=0;i<AMsymbols.length;i++)AMnames[i]=AMsymbols[i].input;}
21−var AMmathml="http://www.w3.org/1998/Math/MathML";function AMcreateElementMathML(t){if(isIE)return document.createElement("m:"+t);else return document.createElementNS(AMmathml,t);}
22−function AMcreateMmlNode(t,frag){if(isIE)var node=document.createElement("m:"+t);else var node=document.createElementNS(AMmathml,t);node.appendChild(frag);return node;}
23−function newcommand(oldstr,newstr){AMsymbols=AMsymbols.concat([{input:oldstr,tag:"mo",output:newstr,ttype:DEFINITION}]);}
24−function AMremoveCharsAndBlanks(str,n){var st;st=str.slice(n);for(var i=0;i<st.length&&st.charCodeAt(i)<=32;i=i+1);return st.slice(i);}
25−function AMposition(arr,str,n){if(n==0){var h,m;n=-1;h=arr.length;while(n+1<h){m=(n+h)>>1;if(arr[m]<str)n=m;else h=m;}
26−return h;}else
27−for(var i=n;i<arr.length&&arr[i]<str;i++);return i;}
28−function AMgetSymbol(str){var k=0;var j=0;var mk;var st;var tagst;var match="";var more=true;for(var i=1;i<=str.length&&more;i++){st=str.slice(0,i);j=k;k=AMposition(AMnames,st,j);if(k<AMnames.length&&str.slice(0,AMnames[k].length)==AMnames[k]){match=AMnames[k];mk=k;i=match.length;}
29−more=k<AMnames.length&&str.slice(0,AMnames[k].length)>=AMnames[k];}
30−AMpreviousSymbol=AMcurrentSymbol;if(match!=""){AMcurrentSymbol=AMsymbols[mk].ttype;return AMsymbols[mk];}
31−AMcurrentSymbol=CONST;k=1;st=str.slice(0,1);if("0"<=st&&st<="9")tagst="mn";else tagst=(("A">st||st>"Z")&&("a">st||st>"z")?"mo":"mi");return{input:st,tag:tagst,output:st,ttype:CONST};}
32−var AMpreviousSymbol,AMcurrentSymbol;function AMparseSexpr(str){var symbol,node,result,result2,i,st,newFrag=document.createDocumentFragment();str=AMremoveCharsAndBlanks(str,0);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
33−return[null,str,null];if(symbol.ttype==DEFINITION){str=symbol.output+AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol==null||symbol.ttype==RIGHTBRACKET)
34−return[null,str,null];}
35−str=AMremoveCharsAndBlanks(str,symbol.input.length);switch(symbol.ttype){case SPACE:node=AMcreateElementMathML(symbol.tag);node.setAttribute(symbol.atname,symbol.atval);return[node,str,symbol.tag];case UNDEROVER:if(isIE){if(symbol.input.substr(0,4)=="\\big"){str="\\"+symbol.input.substr(4)+str;symbol=AMgetSymbol(str);symbol.ttype=UNDEROVER;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
36−return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];case CONST:var output=symbol.output;if(isIE){if(symbol.input=="'")
37−output="\u2032";else if(symbol.input=="''")
38−output="\u2033";else if(symbol.input=="'''")
39−output="\u2033\u2032";else if(symbol.input=="''''")
40−output="\u2033\u2033";else if(symbol.input=="\\square")
41−output="\u25A1";else if(symbol.input.substr(0,5)=="\\frac"){var denom=symbol.input.substr(6,1);if(denom=="5"||denom=="6"){str=symbol.input.replace(/\\frac/,"\\frac ")+str;return[node,str,symbol.tag];}}}
42−node=AMcreateMmlNode(symbol.tag,document.createTextNode(output));return[node,str,symbol.tag];case LONG:node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));node.setAttribute("minsize","1.5");node.setAttribute("maxsize","1.5");node=AMcreateMmlNode("mover",node);node.appendChild(AMcreateElementMathML("mspace"));return[node,str,symbol.tag];case STRETCHY:if(isIE&&symbol.input=="\\backslash")
43−symbol.output="\\";node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(symbol.input=="|"||symbol.input=="\\vert"||symbol.input=="\\|"||symbol.input=="\\Vert"){node.setAttribute("lspace","0em");node.setAttribute("rspace","0em");}
44−node.setAttribute("maxsize",symbol.atval);if(symbol.rtag!=null)
45−return[node,str,symbol.rtag];else
46−return[node,str,symbol.tag];case BIG:var atval=symbol.atval;if(isIE)
47−atval=symbol.ieval;symbol=AMgetSymbol(str);if(symbol==null)
48−return[null,str,null];str=AMremoveCharsAndBlanks(str,symbol.input.length);node=AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height",atval+"ex");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}else{node.setAttribute("minsize",atval);node.setAttribute("maxsize",atval);}
49−return[node,str,symbol.tag];case LEFTBRACKET:if(symbol.input=="\\left"){symbol=AMgetSymbol(str);if(symbol!=null){if(symbol.input==".")
50−symbol.invisible=true;str=AMremoveCharsAndBlanks(str,symbol.input.length);}}
51−result=AMparseExpr(str,true,false);if(symbol==null||(typeof symbol.invisible=="boolean"&&symbol.invisible))
52−node=AMcreateMmlNode("mrow",result[0]);else{node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));node=AMcreateMmlNode("mrow",node);node.appendChild(result[0]);}
53−return[node,result[1],result[2]];case MATRIX:if(symbol.input=="\\begin{array}"){var mask="";symbol=AMgetSymbol(str);str=AMremoveCharsAndBlanks(str,0);if(symbol==null)
54−mask="l";else{str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="{")
55−mask="l";else do{symbol=AMgetSymbol(str);if(symbol!=null){str=AMremoveCharsAndBlanks(str,symbol.input.length);if(symbol.input!="}")
56−mask=mask+symbol.input;}}while(symbol!=null&&symbol.input!=""&&symbol.input!="}");}
57−result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);mask=mask.replace(/l/g,"left ");mask=mask.replace(/r/g,"right ");mask=mask.replace(/c/g,"center ");node.setAttribute("columnalign",mask);node.setAttribute("displaystyle","false");if(isIE)
58−return[node,result[1],null];var lspace=AMcreateElementMathML("mspace");lspace.setAttribute("width","0.167em");var rspace=AMcreateElementMathML("mspace");rspace.setAttribute("width","0.167em");var node1=AMcreateMmlNode("mrow",lspace);node1.appendChild(node);node1.appendChild(rspace);return[node1,result[1],null];}else{result=AMparseExpr("{"+str,true,true);node=AMcreateMmlNode("mtable",result[0]);if(isIE)
59−node.setAttribute("columnspacing","0.25em");else
60−node.setAttribute("columnspacing","0.167em");node.setAttribute("columnalign","right center left");node.setAttribute("displaystyle","true");node=AMcreateMmlNode("mrow",node);return[node,result[1],null];}
61−case TEXT:if(str.charAt(0)=="{")i=str.indexOf("}");else i=0;if(i==-1)
62−i=str.length;st=str.slice(1,i);if(st.charAt(0)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
63−newFrag.appendChild(AMcreateMmlNode(symbol.tag,document.createTextNode(st)));if(st.charAt(st.length-1)==" "){node=AMcreateElementMathML("mspace");node.setAttribute("width","0.33em");newFrag.appendChild(node);}
64−str=AMremoveCharsAndBlanks(str,i+1);return[AMcreateMmlNode("mrow",newFrag),str,null];case UNARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str];if(typeof symbol.func=="boolean"&&symbol.func){st=str.charAt(0);if(st=="^"||st=="_"||st==","){return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}else{node=AMcreateMmlNode("mrow",AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)));if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node.appendChild(space);}
65−node.appendChild(result[0]);return[node,result[1],symbol.tag];}}
66−if(symbol.input=="\\sqrt"){if(isIE){var space=AMcreateElementMathML("mspace");space.setAttribute("height","1.2ex");space.setAttribute("width","0em");node=AMcreateMmlNode(symbol.tag,result[0])
67−node.appendChild(space);return[node,result[1],symbol.tag];}else
68−return[AMcreateMmlNode(symbol.tag,result[0]),result[1],symbol.tag];}else if(typeof symbol.acc=="boolean"&&symbol.acc){node=AMcreateMmlNode(symbol.tag,result[0]);var output=symbol.output;if(isIE){if(symbol.input=="\\hat")
69−output="\u0302";else if(symbol.input=="\\widehat")
70−output="\u005E";else if(symbol.input=="\\bar")
71−output="\u00AF";else if(symbol.input=="\\grave")
72−output="\u0300";else if(symbol.input=="\\tilde")
73−output="\u0303";}
74−var node1=AMcreateMmlNode("mo",document.createTextNode(output));if(symbol.input=="\\vec"||symbol.input=="\\check")
75−node1.setAttribute("maxsize","1.2");if(isIE&&symbol.input=="\\bar")
76−node1.setAttribute("maxsize","0.5");if(symbol.input=="\\underbrace"||symbol.input=="\\underline")
77−node1.setAttribute("accentunder","true");else
78−node1.setAttribute("accent","true");node.appendChild(node1);if(symbol.input=="\\overbrace"||symbol.input=="\\underbrace")
79−node.ttype=UNDEROVER;return[node,result[1],symbol.tag];}else{if(!isIE&&typeof symbol.codes!="undefined"){for(i=0;i<result[0].childNodes.length;i++)
80−if(result[0].childNodes[i].nodeName=="mi"||result[0].nodeName=="mi"){st=(result[0].nodeName=="mi"?result[0].firstChild.nodeValue:result[0].childNodes[i].firstChild.nodeValue);var newst=[];for(var j=0;j<st.length;j++)
81−if(st.charCodeAt(j)>64&&st.charCodeAt(j)<91)newst=newst+
82−String.fromCharCode(symbol.codes[st.charCodeAt(j)-65]);else newst=newst+st.charAt(j);if(result[0].nodeName=="mi")
83−result[0]=AMcreateElementMathML("mo").appendChild(document.createTextNode(newst));else result[0].replaceChild(AMcreateElementMathML("mo").appendChild(document.createTextNode(newst)),result[0].childNodes[i]);}}
84−node=AMcreateMmlNode(symbol.tag,result[0]);node.setAttribute(symbol.atname,symbol.atval);if(symbol.input=="\\scriptstyle"||symbol.input=="\\scriptscriptstyle")
85−node.setAttribute("displaystyle","false");return[node,result[1],symbol.tag];}
86−case BINARY:result=AMparseSexpr(str);if(result[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];result2=AMparseSexpr(result[1]);if(result2[0]==null)return[AMcreateMmlNode("mo",document.createTextNode(symbol.input)),str,null];if(symbol.input=="\\textcolor"||symbol.input=="\\colorbox"){var tclr=str.match(/\{\s*([#\w]+)\s*\}/);str=str.replace(/\{\s*[#\w]+\s*\}/,"");if(tclr!=null){if(IsColorName.test(tclr[1].toLowerCase())){tclr=LaTeXColor[tclr[1].toLowerCase()];}else{tclr=tclr[1];}
87−node=AMcreateElementMathML("mstyle");node.setAttribute(symbol.atval,tclr);node.appendChild(result2[0]);return[node,result2[1],symbol.tag];}}
88−if(symbol.input=="\\root"||symbol.input=="\\stackrel")newFrag.appendChild(result2[0]);newFrag.appendChild(result[0]);if(symbol.input=="\\frac")newFrag.appendChild(result2[0]);return[AMcreateMmlNode(symbol.tag,newFrag),result2[1],symbol.tag];case INFIX:str=AMremoveCharsAndBlanks(str,symbol.input.length);return[AMcreateMmlNode("mo",document.createTextNode(symbol.output)),str,symbol.tag];default:return[AMcreateMmlNode(symbol.tag,document.createTextNode(symbol.output)),str,symbol.tag];}}
89−function AMparseIexpr(str){var symbol,sym1,sym2,node,result,tag,underover;str=AMremoveCharsAndBlanks(str,0);sym1=AMgetSymbol(str);result=AMparseSexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(symbol.ttype==INFIX){str=AMremoveCharsAndBlanks(str,symbol.input.length);result=AMparseSexpr(str);if(result[0]==null)
90−result[0]=AMcreateMmlNode("mo",document.createTextNode("\u25A1"));str=result[1];tag=result[2];if(symbol.input=="_"||symbol.input=="^"){sym2=AMgetSymbol(str);tag=null;underover=((sym1.ttype==UNDEROVER)||(node.ttype==UNDEROVER));if(symbol.input=="_"&&sym2.input=="^"){str=AMremoveCharsAndBlanks(str,sym2.input.length);var res2=AMparseSexpr(str);str=res2[1];tag=res2[2];node=AMcreateMmlNode((underover?"munderover":"msubsup"),node);node.appendChild(result[0]);node.appendChild(res2[0]);}else if(symbol.input=="_"){node=AMcreateMmlNode((underover?"munder":"msub"),node);node.appendChild(result[0]);}else{node=AMcreateMmlNode((underover?"mover":"msup"),node);node.appendChild(result[0]);}
91−node=AMcreateMmlNode("mrow",node);}else{node=AMcreateMmlNode(symbol.tag,node);if(symbol.input=="\\atop"||symbol.input=="\\choose")
92−node.setAttribute("linethickness","0ex");node.appendChild(result[0]);if(symbol.input=="\\choose")
93−node=AMcreateMmlNode("mfenced",node);}}
94−return[node,str,tag];}
95−function AMparseExpr(str,rightbracket,matrix){var symbol,node,result,i,tag,newFrag=document.createDocumentFragment();do{str=AMremoveCharsAndBlanks(str,0);result=AMparseIexpr(str);node=result[0];str=result[1];tag=result[2];symbol=AMgetSymbol(str);if(node!=undefined){if((tag=="mn"||tag=="mi")&&symbol!=null&&typeof symbol.func=="boolean"&&symbol.func){var space=AMcreateElementMathML("mspace");space.setAttribute("width","0.167em");node=AMcreateMmlNode("mrow",node);node.appendChild(space);}
96−newFrag.appendChild(node);}}while((symbol.ttype!=RIGHTBRACKET)&&symbol!=null&&symbol.output!="");tag=null;if(symbol.ttype==RIGHTBRACKET){if(symbol.input=="\\right"){str=AMremoveCharsAndBlanks(str,symbol.input.length);symbol=AMgetSymbol(str);if(symbol!=null&&symbol.input==".")
97−symbol.invisible=true;if(symbol!=null)
98−tag=symbol.rtag;}
99−if(symbol!=null)
100−str=AMremoveCharsAndBlanks(str,symbol.input.length);var len=newFrag.childNodes.length;if(matrix&&len>0&&newFrag.childNodes[len-1].nodeName=="mrow"&&len>1&&newFrag.childNodes[len-2].nodeName=="mo"&&newFrag.childNodes[len-2].firstChild.nodeValue=="&"){var pos=[];var m=newFrag.childNodes.length;for(i=0;matrix&&i<m;i=i+2){pos[i]=[];node=newFrag.childNodes[i];for(var j=0;j<node.childNodes.length;j++)
101−if(node.childNodes[j].firstChild.nodeValue=="&")
102−pos[i][pos[i].length]=j;}
103−var row,frag,n,k,table=document.createDocumentFragment();for(i=0;i<m;i=i+2){row=document.createDocumentFragment();frag=document.createDocumentFragment();node=newFrag.firstChild;n=node.childNodes.length;k=0;for(j=0;j<n;j++){if(typeof pos[i][k]!="undefined"&&j==pos[i][k]){node.removeChild(node.firstChild);row.appendChild(AMcreateMmlNode("mtd",frag));k++;}else frag.appendChild(node.firstChild);}
104−row.appendChild(AMcreateMmlNode("mtd",frag));if(newFrag.childNodes.length>2){newFrag.removeChild(newFrag.firstChild);newFrag.removeChild(newFrag.firstChild);}
105−table.appendChild(AMcreateMmlNode("mtr",row));}
106−return[table,str];}
107−if(typeof symbol.invisible!="boolean"||!symbol.invisible){node=AMcreateMmlNode("mo",document.createTextNode(symbol.output));newFrag.appendChild(node);}}
108−return[newFrag,str,tag];}
109−function AMparseMath(str){var result,node=AMcreateElementMathML("mstyle");var cclr=str.match(/\\color\s*\{\s*([#\w]+)\s*\}/);str=str.replace(/\\color\s*\{\s*[#\w]+\s*\}/g,"");if(cclr!=null){if(IsColorName.test(cclr[1].toLowerCase())){cclr=LaTeXColor[cclr[1].toLowerCase()];}else{cclr=cclr[1];}
110−node.setAttribute("mathcolor",cclr);}else{if(mathcolor!="")node.setAttribute("mathcolor",mathcolor);};if(mathfontfamily!="")node.setAttribute("fontfamily",mathfontfamily);node.appendChild(AMparseExpr(str.replace(/^\s+/g,""),false,false)[0]);node=AMcreateMmlNode("math",node);if(showasciiformulaonhover)
111−node.setAttribute("title",str.replace(/\s+/g," "));if(false){var fnode=AMcreateElementXHTML("font");fnode.setAttribute("face",mathfontfamily);fnode.appendChild(node);return fnode;}
112−return node;}
113−function AMstrarr2docFrag(arr,linebreaks){var newFrag=document.createDocumentFragment();var expr=false;for(var i=0;i<arr.length;i++){if(expr)newFrag.appendChild(AMparseMath(arr[i]));else{var arri=(linebreaks?arr[i].split("\n\n"):[arr[i]]);newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[0])));for(var j=1;j<arri.length;j++){newFrag.appendChild(AMcreateElementXHTML("p"));newFrag.appendChild(AMcreateElementXHTML("span").appendChild(document.createTextNode(arri[j])));}}
114−expr=!expr;}
115−return newFrag;}
116−function AMprocessNodeR(n,linebreaks){var mtch,str,arr,frg,i;if(n.childNodes.length==0){if((n.nodeType!=8||linebreaks)&&n.parentNode.nodeName!="form"&&n.parentNode.nodeName!="FORM"&&n.parentNode.nodeName!="textarea"&&n.parentNode.nodeName!="TEXTAREA"&&n.parentNode.nodeName!="pre"&&n.parentNode.nodeName!="PRE"){str=n.nodeValue;if(!(str==null)){str=str.replace(/\r\n\r\n/g,"\n\n");str=str.replace(/\x20+/g," ");str=str.replace(/\s*\r\n/g," ");mtch=(str.indexOf("\$")==-1?false:true);str=str.replace(/([^\\])\$/g,"$1 \$");str=str.replace(/^\$/," \$");arr=str.split(" \$");for(i=0;i<arr.length;i++)
117−arr[i]=arr[i].replace(/\\\$/g,"\$");if(arr.length>1||mtch){if(checkForMathML){checkForMathML=false;var nd=AMisMathMLavailable();AMnoMathML=nd!=null;if(AMnoMathML&&notifyIfNoMathML)
118−if(alertIfNoMathML)
119−alert("To view the ASCIIMathML notation use Internet Explorer 6 +\nMathPlayer (free from www.dessci.com)\nor Firefox/Mozilla/Netscape");else AMbody.insertBefore(nd,AMbody.childNodes[0]);}
120−if(!AMnoMathML){frg=AMstrarr2docFrag(arr,n.nodeType==8);var len=frg.childNodes.length;n.parentNode.replaceChild(frg,n);return len-1;}else return 0;}}}else return 0;}else if(n.nodeName!="math"){for(i=0;i<n.childNodes.length;i++)
121−i+=AMprocessNodeR(n.childNodes[i],linebreaks);}
122−return 0;}
123−function AMprocessNode(n,linebreaks,spanclassAM){var frag,st;if(spanclassAM!=null){frag=document.getElementsByTagName("span")
124−for(var i=0;i<frag.length;i++)
125−if(frag[i].className=="AM")
126−AMprocessNodeR(frag[i],linebreaks);}else{try{st=n.innerHTML;}catch(err){}
127−if(st==null||st.indexOf("\$")!=-1)
128−AMprocessNodeR(n,linebreaks);}
129−if(isIE){frag=document.getElementsByTagName('math');for(var i=0;i<frag.length;i++)frag[i].update()}}
130−var inAppendix=false;var sectionCntr=0;var IEcommentWarning=true;var biblist=[];var bibcntr=0;var LaTeXCounter=[];LaTeXCounter["definition"]=0;LaTeXCounter["proposition"]=0;LaTeXCounter["lemma"]=0;LaTeXCounter["theorem"]=0;LaTeXCounter["corollary"]=0;LaTeXCounter["example"]=0;LaTeXCounter["exercise"]=0;LaTeXCounter["subsection"]=0;LaTeXCounter["subsubsection"]=0;LaTeXCounter["figure"]=0;LaTeXCounter["equation"]=0;LaTeXCounter["table"]=0;var LaTeXColor=[];LaTeXColor["greenyellow"]="#D9FF4F";LaTeXColor["yellow"]="#FFFF00";LaTeXColor["goldenrod"]="#FFE529";LaTeXColor["dandelion"]="#FFB529";LaTeXColor["apricot"]="#FFAD7A";LaTeXColor["peach"]="#FF804D";LaTeXColor["melon"]="#FF8A80";LaTeXColor["yelloworange"]="#FF9400";LaTeXColor["orange"]="#FF6321";LaTeXColor["burntorange"]="#FF7D00";LaTeXColor["bittersweet"]="#C20300";LaTeXColor["redorange"]="#FF3B21";LaTeXColor["mahogany"]="#A60000";LaTeXColor["maroon"]="#AD0000";LaTeXColor["brickred"]="#B80000";LaTeXColor["red"]="#FF0000";LaTeXColor["orangered"]="#FF0080";LaTeXColor["rubinered"]="#FF00DE";LaTeXColor["wildstrawberry"]="#FF0A9C";LaTeXColor["salmon"]="#FF789E";LaTeXColor["carnationpink"]="#FF5EFF";LaTeXColor["magenta"]="#FF00FF";LaTeXColor["violetred"]="#FF30FF";LaTeXColor["rhodamine"]="#FF2EFF";LaTeXColor["mulberry"]="#A314FA";LaTeXColor["redviolet"]="#9600A8";LaTeXColor["fuchsia"]="#7303EB";LaTeXColor["lavender"]="#FF85FF";LaTeXColor["thistle"]="#E069FF";LaTeXColor["orchid"]="#AD5CFF";LaTeXColor["darkorchid"]="#9933CC";LaTeXColor["purple"]="#8C24FF";LaTeXColor["plum"]="#8000FF";LaTeXColor["violet"]="#361FFF";LaTeXColor["royalpurple"]="#401AFF";LaTeXColor["blueviolet"]="#1A0DF5";LaTeXColor["periwinkle"]="#6E73FF";LaTeXColor["cadetblue"]="#616EC4";LaTeXColor["cornflowerblue"]="#59DEFF";LaTeXColor["midnightblue"]="#007091";LaTeXColor["navyblue"]="#0F75FF";LaTeXColor["royalblue"]="#0080FF";LaTeXColor["blue"]="#0000FF";LaTeXColor["cerulean"]="#0FE3FF";LaTeXColor["cyan"]="#00FFFF";LaTeXColor["processblue"]="#0AFFFF";LaTeXColor["skyblue"]="#61FFE0";LaTeXColor["turquoise"]="#26FFCC";LaTeXColor["tealblue"]="#1FFAA3";LaTeXColor["aquamarine"]="#2EFFB2";LaTeXColor["bluegreen"]="#26FFAB";LaTeXColor["emerald"]="#00FF80";LaTeXColor["junglegreen"]="#03FF7A";LaTeXColor["seagreen"]="#4FFF80";LaTeXColor["green"]="#00FF00";LaTeXColor["forestgreen"]="#00E000";LaTeXColor["pinegreen"]="#00BF29";LaTeXColor["limegreen"]="#80FF00";LaTeXColor["yellowgreen"]="#8FFF42";LaTeXColor["springgreen"]="#BDFF3D";LaTeXColor["olivegreen"]="#009900";LaTeXColor["rawsienna"]="#8C0000";LaTeXColor["sepia"]="#4D0000";LaTeXColor["brown"]="#660000";LaTeXColor["tan"]="#DB9470";LaTeXColor["gray"]="#808080";LaTeXColor["grey"]="#808080";LaTeXColor["black"]="#000000";LaTeXColor["white"]="#FFFFFF";var IsColorName=/^(?:greenyellow|yellow|goldenrod|dandelion|apricot|peach|melon|yelloworange|orange|burntorange|bittersweet|redorange|mahogany|maroon|brickred|red|orangered|rubinered|wildstrawberry|salmon|carnationpink|magenta|violetred|rhodamine|mulberry|redviolet|fuchsia|lavender|thistle|orchid|darkorchid|purple|plum|violet|royalpurple|blueviolet|periwinkle|cadetblue|cornflowerblue|midnightblue|navyblue|royalblue|blue|cerulean|cyan|processblue|skyblue|turquoise|tealblue|aquamarine|bluegreen|emerald|junglegreen|seagreen|green|forestgreen|pinegreen|limegreen|yellowgreen|springgreen|olivegreen|rawsienna|sepia|brown|tan|gray|grey|black|white)$/;var IsCounter=/^(?:definition|proposition|lemma|theorem|corollary|example|exercise|subsection|subsubsection|figure|equation|table)$/;var IsLaTeXElement=/^(?:displayequation|title|author|address|date|abstract|keyword|section|subsection|subsubsection|ref|cite|thebibliography|definition|proposition|lemma|theorem|corollary|example|exercise|itemize|enumerate|enddefinition|endproposition|endlemma|endtheorem|endcorollary|endexample|endexercise|enditemize|endenumerate|LaTeXMathMLlabel|LaTeXMathML|smallskip|medskip|bigskip|quote|quotation|endquote|endquotation|center|endcenter|description|enddescription|inlinemath)$/;var IsTextOnlyArea=/^(?:form|textarea|pre)$/i;var tableid=0;function makeNumberString(cntr){if(sectionCntr>0){if(inAppendix){return"A"+sectionCntr+"."+cntr;}else{return sectionCntr+"."+cntr;}}else{return""+cntr;}};function LaTeXpreProcess(thebody){var TheBody=thebody;if(TheBody.hasChildNodes()){if(!(IsLaTeXElement.test(TheBody.className)))
131−{for(var i=0;i<TheBody.childNodes.length;i++){LaTeXpreProcess(TheBody.childNodes[i])}}}
132−else{if(TheBody.nodeType==3&&!(IsTextOnlyArea.test(TheBody.parentNode.nodeName)))
133−{var str=TheBody.nodeValue;if(!(str==null)){str=str.replace(/\\%/g,"<per>");str=str.replace(/%[^\n]*(?=\n)/g,"");str=str.replace(/%[^\r]*(?=\r)/g,"");str=str.replace(/%[^\n]*$/,"")
134−if(isIE&&str.match(/%/g)!=null&&IEcommentWarning){alert("Comments may not have parsed properly. Try putting in <pre class='LaTeX><div>..</div></pre> structure.");IEcommentWarning=false;}
135−str=str.replace(/<per>/g,"%");if(str.match(/XXX[\s\S]*/)!=null){var tmp=str.match(/XXX[\s\S]*/)[0];var tmpstr=tmp.charCodeAt(7)+"::"+tmp.charCodeAt(8)+"::"+tmp.charCodeAt(9)+"::"+tmp.charCodeAt(10)+"::"+tmp.charCodeAt(11)+"::"+tmp.charCodeAt(12)+"::"+tmp.charCodeAt(13);alert(tmpstr);}
136−str=str.replace(/([^\\])\\(\s)/g,"$1\u00A0$2");str=str.replace(/\\quad/g,"\u2001");str=str.replace(/\\qquad/g,"\u2001\u2001");str=str.replace(/\\enspace/g,"\u2002");str=str.replace(/\\;/g,"\u2004");str=str.replace(/\\:/g,"\u2005");str=str.replace(/\\,/g,"\u2006");str=str.replace(/\\thinspace/g,"\u200A");str=str.replace(/([^\\])~/g,"$1\u00A0");str=str.replace(/\\~/g,"~");str=str.replace(/\\\[/g," <DEQ> $\\displaystyle{");str=str.replace(/\\\]/g,"}$ <DEQ> ");str=str.replace(/\$\$/g,"${$<DEQ>$}$");str=str.replace(/\\begin\s*\{\s*array\s*\}/g,"\\begin{array}");str=str.replace(/\\end\s*\{\s*array\s*\}/g,"\\end{array}");str=str.replace(/\\begin\s*\{\s*eqnarray\s*\}/g," <DEQ>eqno$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*eqnarray\*\s*\}/g," <DEQ>$\\begin{eqnarray}");str=str.replace(/\\end\s*\{\s*eqnarray\*\s*\}/g,"\\end{eqnarray}$<DEQ> ");str=str.replace(/\\begin\s*\{\s*displaymath\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*displaymath\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\*\s*\}/g," <DEQ> $\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\*\s*\}/g,"}$ <DEQ> ");str=str.replace(/\\begin\s*\{\s*equation\s*\}/g," <DEQ>eqno$\\displaystyle{");str=str.replace(/\\end\s*\{\s*equation\s*\}/g,"}$ <DEQ> ");str=str.split("<DEQ>");var newFrag=document.createDocumentFragment();for(var i=0;i<str.length;i++){if(i%2){var DEQtable=document.createElement("table");DEQtable.className='displayequation';var DEQtbody=document.createElement("tbody");var DEQtr=document.createElement("tr");var DEQtdeq=document.createElement("td");DEQtdeq.className='eq';str[i]=str[i].replace(/\$\}\$/g,"$\\displaystyle{");str[i]=str[i].replace(/\$\{\$/g,"}");var lbl=str[i].match(/\\label\s*\{\s*(\w+)\s*\}/);var ISeqno=str[i].match(/^eqno/);str[i]=str[i].replace(/^eqno/," ");str[i]=str[i].replace(/\\label\s*\{\s*\w+\s*\}/," ");DEQtdeq.appendChild(document.createTextNode(str[i]));DEQtr.appendChild(DEQtdeq);str[i]=str[i].replace(/\\nonumber/g,"");if(ISeqno!=null||lbl!=null){var DEQtdno=document.createElement("td");DEQtdno.className='eqno';LaTeXCounter["equation"]++;var eqnoString=makeNumberString(LaTeXCounter["equation"]);var DEQanchor=document.createElement("a");if(lbl!=null){DEQanchor.id=lbl[1]};DEQanchor.className="eqno";var anchorSpan=document.createElement("span");anchorSpan.className="eqno";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(eqnoString));DEQanchor.appendChild(anchorSpan);DEQtdno.appendChild(DEQanchor);var DEQspan=document.createElement("span");DEQspan.className="eqno";DEQspan.appendChild(document.createTextNode("("+eqnoString+")"));DEQtdno.appendChild(DEQspan);DEQtr.appendChild(DEQtdno);}
137−DEQtbody.appendChild(DEQtr);DEQtable.appendChild(DEQtbody);newFrag.appendChild(DEQtable);}
138−else{str[i]=str[i].replace(/\$\}\$/g,"");str[i]=str[i].replace(/\$\{\$/g,"");str[i]=str[i].replace(/\\maketitle/g,"");str[i]=str[i].replace(/\\begin\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\end\s*\{\s*document\s*\}/g,"");str[i]=str[i].replace(/\\documentclass[^\}]*?\}/g,"");str[i]=str[i].replace(/\\usepackage[^\}]*?\}/g,"");str[i]=str[i].replace(/\\noindent/g,"");str[i]=str[i].replace(/\\notag/g,"");str[i]=str[i].replace(/\\ref\s*\{\s*(\w+)\}/g," \\[ref\\]$1\\[ ");str[i]=str[i].replace(/\\url\s*\{\s*([^\}\n]+)\}/g," \\[url\\]$1\\[ ");str[i]=str[i].replace(/\\href\s*\{\s*([^\}]+)\}\s*\{\s*([^\}]+)\}/g," \\[href\\]$1\\]$2\\[ ");str[i]=str[i].replace(/\\cite\s*\{\s*(\w+)\}/g," \\[cite\\]$1\\[ ");str[i]=str[i].replace(/\\qed/g,"\u220E");str[i]=str[i].replace(/\\endproof/g,"\u220E");str[i]=str[i].replace(/\\proof/g,"\\textbf{Proof: }");str[i]=str[i].replace(/\\n(?=\s)/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\newline/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\linebreak/g," \\[br\\] \\[ ");str[i]=str[i].replace(/\\smallskip/g," \\[logicalbreak\\]smallskip\\[ ");str[i]=str[i].replace(/\\medskip/g," \\[logicalbreak\\]medskip\\[ ");str[i]=str[i].replace(/\\bigskip/g," \\[logicalbreak\\]bigskip\\[ ");str[i]=str[i].replace(/[\n\r]+[ \f\n\r\t\v\u2028\u2029]*[\n\r]+/g," \\[logicalbreak\\]LaTeXMathML\\[ ");if(isIE){str[i]=str[i].replace(/\r/g," ");}
139−str[i]=str[i].replace(/\\bibitem\s*([^\{]*\{\s*\w*\s*\})/g," \\[bibitem\\]$1\\[ ");str[i]=str[i].replace(/\\bibitem\s*/g," \\[bibitem\\] \\[ ");str[i]=str[i].replace(/\\item\s*\[\s*(\w+)\s*\]/g," \\[alistitem\\]$1\\[ ");str[i]=str[i].replace(/\\item\s*/g," \\[alistitem\\] \\[ ");str[i]=str[i].replace(/\\appendix/g," \\[appendix\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*figure\s*\}([\s\S]+?)\\end\s*\{\s*figure\s*\}/g," \\[figure\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*table\s*\}([\s\S]+?)\\end\s*\{\s*table\s*\}/g," \\[table\\]$1\\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*theorem\s*\}/g," \\[theorem\\]Theorem \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*theorem\s*\}/g," \\[endtheorem\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*definition\s*\}/g," \\[definition\\]Definition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*definition\s*\}/g," \\[enddefinition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*lemma\s*\}/g," \\[lemma\\]Lemma \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*lemma\s*\}/g," \\[endlemma\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*corollary\s*\}/g," \\[corollary\\]Corollary \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*corollary\s*\}/g," \\[endcorollary\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proposition\s*\}/g," \\[proposition\\]Proposition \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*proposition\s*\}/g," \\[endproposition\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*example\s*\}/g," \\[example\\]Example \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*example\s*\}/g," \\[endexample\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*exercise\s*\}/g," \\[exercise\\]Exercise \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*exercise\s*\}/g," \\[endexercise\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}\s*\{\s*\w+\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*thebibliography\s*\}/g," \\[thebibliography\\]References \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*thebibliography\s*\}/g," \\[endthebibliography\\]References \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*proof\s*\}/g," \\[proof\\]Proof: \\[ ");if(isIE){str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g,"\u220E \\[endproof\\] \\[ ");}else{str[i]=str[i].replace(/\\end\s*\{\s*proof\s*\}/g," \\[endproof\\] \\[ ");}
140−str[i]=str[i].replace(/\\title\s*\{\s*([^\}]+)\}/g," \\[title\\] \\[$1 \\[endtitle\\] \\[ ");str[i]=str[i].replace(/\\author\s*\{\s*([^\}]+)\}/g," \\[author\\] \\[$1 \\[endauthor\\] \\[ ");str[i]=str[i].replace(/\\address\s*\{\s*([^\}]+)\}/g," \\[address\\] \\[$1 \\[endaddress\\] \\[ ");str[i]=str[i].replace(/\\date\s*\{\s*([^\}]+)\}/g," \\[date\\] \\[$1 \\[enddate\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*keyword\s*\}/g," \\[keyword\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*keyword\s*\}/g," \\[endkeyword\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*abstract\s*\}/g," \\[abstract\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*abstract\s*\}/g," \\[endabstract\\] \\[ ");str[i]=str[i].replace(/\\begin\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[$1\\] \\[ ");str[i]=str[i].replace(/\\end\s*\{\s*(?!array|tabular)(\w+)\s*\}/g," \\[end$1\\] \\[ ");var sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\section\s*\{/," \\[section\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\section\s*\{\s*[\s\S]+\}/);}
141−sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsection\s*\{/," \\[subsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsection\s*\{\s*[\s\S]+\}/);}
142−sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);while(sectionIndex>=0){str[i]=str[i].replace(/\\subsubsection\s*\{/," \\[subsubsection\\]");var delimcnt=1;for(var ii=sectionIndex;ii<str[i].length;ii++){if(str[i].charAt(ii)=="{"){delimcnt++};if(str[i].charAt(ii)=="}"){delimcnt--};if(delimcnt==0){str[i]=str[i].substring(0,ii)+"\\[ "+str[i].substring(ii+1,str[i].length);break;}};sectionIndex=str[i].search(/\\subsubsection\s*\{\s*[\s\S]+\}/);}
143−var CatToNextEven="";var strtmp=str[i].split("\\[");for(var j=0;j<strtmp.length;j++){if(j%2){var strtmparray=strtmp[j].split("\\]");switch(strtmparray[0]){case"section":var nodeTmp=document.createElement("H2");nodeTmp.className='section';sectionCntr++;for(var div in LaTeXCounter){LaTeXCounter[div]=0};var nodeAnchor=document.createElement("a");if(inAppendix){nodeAnchor.className='appendixsection';}else{nodeAnchor.className='section';}
144−var nodeNumString=makeNumberString("");var anchorSpan=document.createElement("span");anchorSpan.className="section";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='section';nodeSpan.appendChild(document.createTextNode(nodeNumString+" "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsection":var nodeTmp=document.createElement("H3");nodeTmp.className='subsection';LaTeXCounter["subsection"]++;LaTeXCounter["subsubsection"]=0;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"subsubsection":var nodeTmp=document.createElement("H4");nodeTmp.className='subsubsection';LaTeXCounter["subsubsection"]++;var nodeAnchor=document.createElement("a");nodeAnchor.className='subsubsection';var nodeNumString=makeNumberString(LaTeXCounter["subsection"]+"."+LaTeXCounter["subsubsection"]);var anchorSpan=document.createElement("span");anchorSpan.className="subsubsection";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(nodeNumString));nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className='subsubsection';nodeSpan.appendChild(document.createTextNode(nodeNumString+". "));nodeTmp.appendChild(nodeSpan);nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"href":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"url":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathML';nodeTmp.href=strtmparray[1];nodeTmp.appendChild(document.createTextNode(strtmparray[1]));newFrag.appendChild(nodeTmp);break;case"figure":var nodeTmp=document.createElement("table");nodeTmp.className='figure';var FIGtbody=document.createElement("tbody");var FIGlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var FIGcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;FIGcap=tmp.substring(capstart,pos);break}}}
145−var FIGtr2=document.createElement("tr");var FIGtd2=document.createElement("td");FIGtd2.className="caption";var FIGanchor=document.createElement("a");FIGanchor.className="figure";if(FIGlbl!=null){FIGanchor.id=FIGlbl[1];}
146−LaTeXCounter["figure"]++;var fignmbr=makeNumberString(LaTeXCounter["figure"]);var anchorSpan=document.createElement("span");anchorSpan.className="figure";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(fignmbr));FIGanchor.appendChild(anchorSpan);FIGtd2.appendChild(FIGanchor);var FIGspan=document.createElement("span");FIGspan.className="figure";FIGspan.appendChild(document.createTextNode("Figure "+fignmbr+". "));FIGtd2.appendChild(FIGspan);FIGtd2.appendChild(document.createTextNode(""+FIGcap));FIGtr2.appendChild(FIGtd2);FIGtbody.appendChild(FIGtr2);var IsSpecial=false;var FIGinfo=strtmparray[1].match(/\\includegraphics\s*\{([^\}]+)\}/);if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\includegraphics\s*\[[^\]]*\]\s*\{\s*([^\}]+)\s*\}/);}
147−if(FIGinfo==null){FIGinfo=strtmparray[1].match(/\\special\s*\{\s*([^\}]+)\}/);IsSpecial=true};if(FIGinfo!=null){var FIGtr1=document.createElement("tr");var FIGtd1=document.createElement("td");FIGtd1.className="image";var FIGimg=document.createElement("img");var FIGsrc=FIGinfo[1];FIGimg.src=FIGsrc;FIGimg.alt="Figure "+FIGsrc+" did not load";FIGimg.title="Figure "+fignmbr+". "+FIGcap;FIGimg.id="figure"+fignmbr;FIGtd1.appendChild(FIGimg);FIGtr1.appendChild(FIGtd1);FIGtbody.appendChild(FIGtr1);}
148−nodeTmp.appendChild(FIGtbody);newFrag.appendChild(nodeTmp);break;case"table":var nodeTmp=document.createElement("table");if(strtmparray[1].search(/\\centering/)>=0){nodeTmp.className='LaTeXtable centered';nodeTmp.align="center";}else{nodeTmp.className='LaTeXtable';};tableid++;nodeTmp.id="LaTeXtable"+tableid;var TABlbl=strtmparray[1].match(/\\label\s*\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\\label\s*\{\w+\}/g,"");var capIndex=strtmparray[1].search(/\\caption\s*\{[\s\S]+\}/);var TABcap="";if(capIndex>=0){var tmp=strtmparray[1];var delimcnt=0;var capstart=-1;for(var pos=capIndex;pos<tmp.length;pos++){if(tmp.charAt(pos)=="{"){delimcnt++};if(tmp.charAt(pos)=="}"){delimcnt--};if(delimcnt==1&&capstart<0){capstart=pos+1};if(delimcnt==0&&capstart>0){capend=pos-1;TABcap=tmp.substring(capstart,pos);break}}}
149−if(TABcap!=""){var TABtbody=document.createElement("tbody");var TABcaption=document.createElement("caption");TABcaption.className="LaTeXtable centered";var TABanchor=document.createElement("a");TABanchor.className="LaTeXtable";if(TABlbl!=null){TABanchor.id=TABlbl[1];}
150−LaTeXCounter["table"]++;var tabnmbr=makeNumberString(LaTeXCounter["table"]);var anchorSpan=document.createElement("span");anchorSpan.className="LaTeXtable";anchorSpan.style.display="none";anchorSpan.appendChild(document.createTextNode(tabnmbr));TABanchor.appendChild(anchorSpan);TABcaption.appendChild(TABanchor);var TABspan=document.createElement("span");TABspan.className="LaTeXtable";TABspan.appendChild(document.createTextNode("Table "+tabnmbr+". "));TABcaption.appendChild(TABspan);TABcaption.appendChild(document.createTextNode(""+TABcap));nodeTmp.appendChild(TABcaption);}
151−var TABinfo=strtmparray[1].match(/\\begin\s*\{\s*tabular\s*\}([\s\S]+)\\end\s*\{\s*tabular\s*\}/);if(TABinfo!=null){var TABtbody=document.createElement('tbody');var TABrow=null;var TABcell=null;var row=0;var col=0;var TABalign=TABinfo[1].match(/^\s*\{([^\}]+)\}/);TABinfo=TABinfo[1].replace(/^\s*\{[^\}]+\}/,"");TABinfo=TABinfo.replace(/\\hline/g,"");TABalign[1]=TABalign[1].replace(/\|/g,"");TABalign[1]=TABalign[1].replace(/\s/g,"");TABinfo=TABinfo.split("\\\\");for(row=0;row<TABinfo.length;row++){TABrow=document.createElement("tr");TABinfo[row]=TABinfo[row].split("&");for(col=0;col<TABinfo[row].length;col++){TABcell=document.createElement("td");switch(TABalign[1].charAt(col)){case"l":TABcell.align="left";break;case"c":TABcell.align="center";break;case"r":TABcell.align="right";break;default:TABcell.align="left";};TABcell.appendChild(document.createTextNode(TABinfo[row][col]));TABrow.appendChild(TABcell);}
152−TABtbody.appendChild(TABrow);}
153−nodeTmp.appendChild(TABtbody);}
154−newFrag.appendChild(nodeTmp);break;case"logicalbreak":var nodeTmp=document.createElement("p");nodeTmp.className=strtmparray[1];nodeTmp.appendChild(document.createTextNode("\u00A0"));newFrag.appendChild(nodeTmp);break;case"appendix":inAppendix=true;sectionCntr=0;break;case"alistitem":var EndDiv=document.createElement("div");EndDiv.className="endlistitem";newFrag.appendChild(EndDiv);var BegDiv=document.createElement("div");BegDiv.className="listitem";if(strtmparray[1]!=" "){var BegSpan=document.createElement("span");BegSpan.className="listitemmarker";var boldBegSpan=document.createElement("b");boldBegSpan.appendChild(document.createTextNode(strtmparray[1]+" "));BegSpan.appendChild(boldBegSpan);BegDiv.appendChild(BegSpan);}
155−newFrag.appendChild(BegDiv);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"bibitem":newFrag.appendChild(document.createElement("br"));var nodeTmp=document.createElement("a");nodeTmp.className='bibitem';var nodeSpan=document.createElement("span");nodeSpan.className='bibitem';bibcntr++;var lbl=strtmparray[1].match(/\{\s*(\w+)\s*\}/);strtmparray[1]=strtmparray[1].replace(/\s*\{\s*\w+\s*\}/g,"");strtmparray[1]=strtmparray[1].replace(/^\s*\[/,"");strtmparray[1]=strtmparray[1].replace(/\s*\]$/,"");strtmparray[1]=strtmparray[1].replace(/^\s+|\s+$/g,"");if(lbl==null){biblist[bibcntr]="bibitem"+bibcntr}else{biblist[bibcntr]=lbl[1];};nodeTmp.name=biblist[bibcntr];nodeTmp.id=biblist[bibcntr];if(strtmparray[1]!=""){nodeSpan.appendChild(document.createTextNode(strtmparray[1]));}else{nodeSpan.appendChild(document.createTextNode("["+bibcntr+"]"));}
156−nodeTmp.appendChild(nodeSpan);newFrag.appendChild(nodeTmp);break;case"cite":var nodeTmp=document.createElement("a");nodeTmp.className='cite';nodeTmp.name='cite';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;case"ref":var nodeTmp=document.createElement("a");nodeTmp.className='ref';nodeTmp.name='ref';nodeTmp.href="#"+strtmparray[1];newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("div");nodeTmp.className=strtmparray[0];if(IsCounter.test(strtmparray[0])){LaTeXCounter[strtmparray[0]]++;var nodeAnchor=document.createElement("a");nodeAnchor.className=strtmparray[0];var divnum=makeNumberString(LaTeXCounter[strtmparray[0]]);var anchorSpan=document.createElement("span");anchorSpan.className=strtmparray[0];anchorSpan.appendChild(document.createTextNode(divnum));anchorSpan.style.display="none";nodeAnchor.appendChild(anchorSpan);nodeTmp.appendChild(nodeAnchor);var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]+" "+divnum+". "));nodeTmp.appendChild(nodeSpan);}
157−if(isIE){if(strtmparray[0]==("thebibliography"||"abstract"||"keyword"||"proof")){var nodeSpan=document.createElement("span");nodeSpan.className=strtmparray[0];nodeSpan.appendChild(document.createTextNode(strtmparray[1]));nodeTmp.appendChild(nodeSpan);}}
158−if(strtmparray[0]=="endenumerate"||strtmparray[0]=="enditemize"||strtmparray[0]=="enddescription"){var endDiv=document.createElement("div");endDiv.className="endlistitem";newFrag.appendChild(endDiv);}
159−newFrag.appendChild(nodeTmp);if(strtmparray[0]=="enumerate"||strtmparray[0]=="itemize"||strtmparray[0]=="description"){var endDiv=document.createElement("div");endDiv.className="listitem";newFrag.appendChild(endDiv);}}}else{strtmp[j]=strtmp[j].replace(/\\\$/g,"<per>");strtmp[j]=strtmp[j].replace(/\$([^\$]+)\$/g," \\[$1\\[ ");strtmp[j]=strtmp[j].replace(/<per>/g,"\\$");strtmp[j]=strtmp[j].replace(/\\begin\s*\{\s*math\s*\}([\s\S]+?)\\end\s*\{\s*math\s*\}/g," \\[$1\\[ ");var strtmptmp=strtmp[j].split("\\[");for(var jjj=0;jjj<strtmptmp.length;jjj++){if(jjj%2){var nodeTmp=document.createElement("span");nodeTmp.className='inlinemath';nodeTmp.appendChild(document.createTextNode("$"+strtmptmp[jjj]+"$"));newFrag.appendChild(nodeTmp);}else{var TagIndex=strtmptmp[jjj].search(/\\\w+/);var tmpIndex=TagIndex;while(tmpIndex>-1){if(/^\\textcolor/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\textcolor\s*\{\s*(\w+)\s*\}\s*/," \\[textcolor\\]$1\\]|");}else{if(/^\\colorbox/.test(strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length))){strtmptmp[jjj]=strtmptmp[jjj].replace(/\\colorbox\s*\{\s*(\w+)\s*\}\s*/," \\[colorbox\\]$1\\]|");}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).replace(/\\\s*(\w+)\s*/," \\[$1\\]|");}}
160−TagIndex+=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\|/);TagIndex++;strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\]\|/,"\\] ");if(strtmptmp[jjj].charAt(TagIndex)=="{"){strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);var delimcnt=1;for(var kk=TagIndex;kk<strtmptmp[jjj].length;kk++){if(strtmptmp[jjj].charAt(kk)=="{"){delimcnt++};if(strtmptmp[jjj].charAt(kk)=="}"){delimcnt--};if(delimcnt==0){break;}}
161−strtmptmp[jjj]=strtmptmp[jjj].substring(0,kk)+"\\[ "+strtmptmp[jjj].substring(kk+1,strtmptmp[jjj].length);TagIndex=kk+3;}else{strtmptmp[jjj]=strtmptmp[jjj].substring(0,TagIndex)+"\\[ "+strtmptmp[jjj].substring(TagIndex+1,strtmptmp[jjj].length);TagIndex=TagIndex+3;}
162−if(TagIndex<strtmptmp[jjj].length){tmpIndex=strtmptmp[jjj].substring(TagIndex,strtmptmp[jjj].length).search(/\\\w+/);}
163−else{tmpIndex=-1};TagIndex+=tmpIndex;}
164−strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\\s*\\\\/g,"\\\\");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\\\/g," \\[br\\] \\[ ");strtmptmp[jjj]=strtmptmp[jjj].replace(/\\label\s*\{\s*(\w+)\s*\}/g," \\[a\\]$1\\[ ");var strlbls=strtmptmp[jjj].split("\\[");for(var jj=0;jj<strlbls.length;jj++){if(jj%2){var strtmparray=strlbls[jj].split("\\]");switch(strtmparray[0]){case"textcolor":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.color=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.color=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"colorbox":var nodeTmp=document.createElement("span");nodeTmp.className='LaTeXColor';if(IsColorName.test(strtmparray[1].toLowerCase())){nodeTmp.style.background=LaTeXColor[strtmparray[1].toLowerCase()];}else{nodeTmp.style.background=strtmparray[1];};nodeTmp.appendChild(document.createTextNode(strtmparray[2]));newFrag.appendChild(nodeTmp);break;case"br":newFrag.appendChild(document.createElement("br"));break;case"a":var nodeTmp=document.createElement("a");nodeTmp.className='LaTeXMathMLlabel';nodeTmp.id=strtmparray[1];nodeTmp.style.display="none";newFrag.appendChild(nodeTmp);break;default:var nodeTmp=document.createElement("span");nodeTmp.className=strtmparray[0];nodeTmp.appendChild(document.createTextNode(strtmparray[1]))
165−newFrag.appendChild(nodeTmp);}}else{newFrag.appendChild(document.createTextNode(strlbls[jj]));}}}}}}}};TheBody.parentNode.replaceChild(newFrag,TheBody);}}}
166−return TheBody;}
167−function LaTeXDivsAndRefs(thebody){var TheBody=thebody;var EndDivClass=null;var AllDivs=TheBody.getElementsByTagName("div");var lbl2id="";var lblnode=null;for(var i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){EndDivClass=EndDivClass[0];var DivClass=EndDivClass.substring(3,EndDivClass.length);var EndDivNode=AllDivs[i];break;}}
168−while(EndDivClass!=null){var newFrag=document.createDocumentFragment();var RootNode=EndDivNode.parentNode;var ClassCount=1;while(EndDivNode.previousSibling!=null&&ClassCount>0){switch(EndDivNode.previousSibling.className){case EndDivClass:ClassCount++;newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);break;case DivClass:if(EndDivNode.previousSibling.nodeName=="DIV"){ClassCount--;if(lbl2id!=""){EndDivNode.previousSibling.id=lbl2id;lbl2id=""}
169−if(ClassCount==0){RootNode=EndDivNode.previousSibling;}else{newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}};break;case'LaTeXMathMLlabel':lbl2id=EndDivNode.previousSibling.id;EndDivNode.parentNode.removeChild(EndDivNode.previousSibling);break;default:newFrag.insertBefore(EndDivNode.previousSibling,newFrag.firstChild);}}
170−RootNode.appendChild(newFrag);EndDivNode.parentNode.removeChild(EndDivNode);AllDivs=TheBody.getElementsByTagName("DIV");for(i=AllDivs.length-1;i>=0;i--){EndDivClass=AllDivs[i].className.match(/end\w+/);if(EndDivClass!=null){ClassCount=0;EndDivClass=EndDivClass[0];DivClass=EndDivClass.substring(3,EndDivClass.length);EndDivNode=AllDivs[i];RootNode=EndDivNode.parentNode;break;}}}
171−var AllDivs=TheBody.getElementsByTagName("div");var DIV2LI=null;for(var i=0;i<AllDivs.length;i++){if(AllDivs[i].className=="itemize"||AllDivs[i].className=="enumerate"||AllDivs[i].className=="description"){if(AllDivs[i].className=="itemize"){RootNode=document.createElement("UL");}else{RootNode=document.createElement("OL");}
172−RootNode.className='LaTeXMathML';if(AllDivs[i].hasChildNodes()){AllDivs[i].removeChild(AllDivs[i].firstChild)};while(AllDivs[i].hasChildNodes()){if(AllDivs[i].firstChild.hasChildNodes()){DIV2LI=document.createElement("LI");while(AllDivs[i].firstChild.hasChildNodes()){DIV2LI.appendChild(AllDivs[i].firstChild.firstChild);}
173−if(DIV2LI.firstChild.className=="listitemmarker"){DIV2LI.style.listStyleType="none";}
174−RootNode.appendChild(DIV2LI)}
175−AllDivs[i].removeChild(AllDivs[i].firstChild);}
176−AllDivs[i].appendChild(RootNode);}}
177−var AllAnchors=TheBody.getElementsByTagName("a");for(var i=0;i<AllAnchors.length;i++){if(AllAnchors[i].className=="ref"||AllAnchors[i].className=="cite"){var label=AllAnchors[i].href.match(/\#(\w+)/);if(label!=null){var labelNode=document.getElementById(label[1]);if(labelNode!=null){var TheSpans=labelNode.getElementsByTagName("SPAN");if(TheSpans!=null){var refNode=TheSpans[0].cloneNode(true);refNode.style.display="inline"
178−refNode.className=AllAnchors[i].className;AllAnchors[i].appendChild(refNode);}}}}}
179−return TheBody;}
180−var AMbody;var AMnoMathML=false,AMtranslated=false;function translate(spanclassAM){if(!AMtranslated){AMtranslated=true;AMinitSymbols();var LaTeXContainers=[];var AllContainers=document.getElementsByTagName('*');var ExtendName="";for(var k=0,l=0;k<AllContainers.length;k++){ExtendName=" "+AllContainers[k].className+" ";if(ExtendName.match(/\sLaTeX\s/)!=null){LaTeXContainers[l]=AllContainers[k];l++;}};if(LaTeXContainers.length>0){for(var m=0;m<LaTeXContainers.length;m++){AMbody=LaTeXContainers[m];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
181−if(AMbody.tagName=="PRE"){var PreChilds=document.createDocumentFragment();var DivChilds=document.createElement("DIV");while(AMbody.hasChildNodes()){DivChilds.appendChild(AMbody.firstChild);}
182−PreChilds.appendChild(DivChilds);AMbody.parentNode.replaceChild(PreChilds,AMbody);AMbody=DivChilds;}
183−AMprocessNode(AMbody,false,spanclassAM);}}else{AMbody=document.getElementsByTagName("body")[0];try{AMbody=LaTeXDivsAndRefs(LaTeXpreProcess(AMbody));}catch(err){alert("Unknown Error: Defaulting to Original LaTeXMathML");}
184−AMprocessNode(AMbody,false,spanclassAM);}}}
185−if(isIE){document.write("<object id=\"mathplayer\" classid=\"clsid:32F66A20-7614-11D4-BD11-00104BD3F987\"></object>");document.write("<?import namespace=\"m\" implementation=\"#mathplayer\"?>");}
186−function generic()
187−{translate();};if(typeof window.addEventListener!='undefined')
188−{window.addEventListener('load',generic,false);}
189−else if(typeof document.addEventListener!='undefined')
190−{document.addEventListener('load',generic,false);}
191−else if(typeof window.attachEvent!='undefined')
192−{window.attachEvent('onload',generic);}
193−else
194−{if(typeof window.onload=='function')
195−{var existing=onload;window.onload=function()
196−{existing();generic();};}
197−else
198−{window.onload=generic;}}
data/bash_completion.tpl+3−3
@@ -4,7 +4,7 @@
44
55_pandoc()
66{
7− local cur prev opts lastc informats outformats datadir
7+ local cur prev opts lastc informats outformats datafiles
88 COMPREPLY=()
99 cur="${COMP_WORDS[COMP_CWORD]}"
1010 prev="${COMP_WORDS[COMP_CWORD-1]}"
@@ -14,7 +14,7 @@ _pandoc()
1414 informats="%s"
1515 outformats="%s"
1616 highlight_styles="%s"
17− datadir="%s"
17+ datafiles="%s"
1818
1919 case "${prev}" in
2020 --from|-f|--read|-r)
@@ -34,7 +34,7 @@ _pandoc()
3434 return 0
3535 ;;
3636 --print-default-data-file)
37− COMPREPLY=( $(compgen -W "reference.odt reference.docx $(find ${datadir} | sed -e 's/.*\/data\///')" -- ${cur}) )
37+ COMPREPLY=( $(compgen -W "${datafiles}" -- ${cur}) )
3838 return 0
3939 ;;
4040 --wrap)
data/pptx/docProps/thumbnail.jpegdeleted

Binary file not shown.

data/templates/default.context+8−1
@@ -38,6 +38,13 @@ $endif$
3838$if(pagenumbering)$
3939\setuppagenumbering[$for(pagenumbering)$$pagenumbering$$sep$,$endfor$]
4040$endif$
41+$if(pdfa)$
42+% attempt to generate PDF/A
43+\setupbackend
44+ [format=PDF/A-1b:2005,
45+ intent=sRGB IEC61966-2.1,
46+ profile=sRGB.icc]
47+$endif$
4148
4249% use microtypography
4350\definefontfeature[default][default][script=latn, protrusion=quality, expansion=quality, itlc=yes, textitalics=yes, onum=yes, pnum=yes]
@@ -47,7 +54,7 @@ $endif$
4754
4855\setupbodyfontenvironment[default][em=italic] % use italic as em, not slanted
4956
50−\definefallbackfamily[mainface][rm][DejaVu Serif][preset=range:greek, force=yes]
57+\definefallbackfamily[mainface][rm][CMU Serif][preset=range:greek, force=yes]
5158\definefontfamily[mainface][rm][$if(mainfont)$$mainfont$$else$Latin Modern Roman$endif$]
5259\definefontfamily[mainface][mm][$if(mathfont)$$mathfont$$else$Latin Modern Math$endif$]
5360\definefontfamily[mainface][ss][$if(sansfont)$$sansfont$$else$Latin Modern Sans$endif$]
data/templates/default.html5+1−1
@@ -29,7 +29,7 @@ $highlighting-css$
2929 </style>
3030$endif$
3131$for(css)$
32− <link rel="stylesheet" href="$css$">
32+ <link rel="stylesheet" href="$css$" />
3333$endfor$
3434$if(math)$
3535 $math$
data/templates/default.latex+12−6
@@ -2,14 +2,24 @@
22\PassOptionsToPackage{hyphens}{url}
33$if(colorlinks)$
44\PassOptionsToPackage{dvipsnames,svgnames*,x11names*}{xcolor}
5−$endif$
6−%
5+$endif$$if(dir)$$if(latex-dir-rtl)$
6+\PassOptionsToPackage{RTLdocument}{bidi}
7+$endif$$endif$%
78\documentclass[$if(fontsize)$$fontsize$,$endif$$if(lang)$$babel-lang$,$endif$$if(papersize)$$papersize$paper,$endif$$if(beamer)$ignorenonframetext,$if(handout)$handout,$endif$$if(aspectratio)$aspectratio=$aspectratio$,$endif$$endif$$for(classoption)$$classoption$$sep$,$endfor$]{$documentclass$}
89$if(beamer)$
10+$if(background-image)$
11+\usebackgroundtemplate{%
12+\includegraphics[width=\paperwidth]{$background-image$}%
13+}
14+$endif$
15+\usepackage{pgfpages}
916\setbeamertemplate{caption}[numbered]
1017\setbeamertemplate{caption label separator}{: }
1118\setbeamercolor{caption name}{fg=normal text.fg}
1219\beamertemplatenavigationsymbols$if(navigation)$$navigation$$else$empty$endif$
20+$for(beameroption)$
21+\setbeameroption{$beameroption$}
22+$endfor$
1323$endif$
1424$if(beamerarticle)$
1525\usepackage{beamerarticle} % needs to be loaded first
@@ -287,11 +297,7 @@ $endif$
287297$if(dir)$
288298\ifxetex
289299 % load bidi as late as possible as it modifies e.g. graphicx
290− $if(latex-dir-rtl)$
291− \usepackage[RTLdocument]{bidi}
292− $else$
293300 \usepackage{bidi}
294− $endif$
295301\fi
296302\ifnum 0\ifxetex 1\fi\ifluatex 1\fi=0 % if pdftex
297303 \TeXXeTstate=1
data/templates/default.ms+4−1
@@ -90,7 +90,10 @@ $for(author)$
9090$author$
9191$endfor$
9292$if(date)$
93−.ND "$date$"
93+.AU
94+.sp 0.5
95+.ft R
96+$date$
9497$endif$
9598$if(abstract)$
9699.AB
data/templates/default.revealjs+5
@@ -197,6 +197,11 @@ $endif$
197197$if(parallaxBackgroundImage)$
198198 // Parallax background image
199199 parallaxBackgroundImage: '$parallaxBackgroundImage$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
200+$else$
201+$if(background-image)$
202+ // Parallax background image
203+ parallaxBackgroundImage: '$background-image$', // e.g. "'https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg'"
204+$endif$
200205$endif$
201206$if(parallaxBackgroundSize)$
202207 // Parallax background size
doc/lua-filters.md+37−4
@@ -135,9 +135,42 @@ Elements without matching functions are left untouched.
135135See [module documentation](#module-pandoc) for a list of pandoc
136136elements.
137137
138−The global `FORMAT` is set to the format of the pandoc writer
139−being used (`html5`, `latex`, etc.), so the behavior of a filter
140−can be made conditional on the eventual output format.
138+
139+## Global variables
140+
141+Pandoc passes additional data to Lua filters by setting global
142+variables.
143+
144+`FORMAT`
145+: The global `FORMAT` is set to the format of the pandoc
146+ writer being used (`html5`, `latex`, etc.), so the behavior
147+ of a filter can be made conditional on the eventual output
148+ format.
149+
150+`PANDOC_READER_OPTIONS`
151+: Table of the options which were provided to the parser.
152+
153+`PANDOC_VERSION`
154+: Contains the pandoc version as a numerically indexed table,
155+ most significant number first. E.g., for pandoc 2.1.1, the
156+ value of the variable is a table `{2, 1, 1}`. Use
157+ `table.concat(PANDOC_VERSION, '.')` to produce a version
158+ string. This variable is also set in custom writers.
159+
160+`PANDOC_API_VERSION`
161+: Contains the version of the pandoc-types API against which
162+ pandoc was compiled. It is given as a numerically indexed
163+ table, most significant number first. E.g., if pandoc was
164+ compiled against pandoc-types 1.17.3, then the value of the
165+ variable will be a table `{1, 17, 3}`. Use
166+ `table.concat(PANDOC_API_VERSION, '.')` to produce a version
167+ string from this table. This variable is also set in custom
168+ writers.
169+
170+`PANDOC_SCRIPT_FILE`
171+: The name used to involve the filter. This value can be used
172+ to find files relative to the script file. This variable is
173+ also set in custom writers.
141174
142175# Pandoc Module
143176
@@ -318,7 +351,7 @@ local vars = {}
318351function get_vars (meta)
319352 for k, v in pairs(meta) do
320353 if v.t == 'MetaInlines' then
321− vars["$" .. k .. "$"] = v
354+ vars["$" .. k .. "$"] = {table.unpack(v)}
322355 end
323356 end
324357end
doc/org.mdnew file+95
@@ -0,0 +1,95 @@
1+---
2+title: Org-mode features and differences
3+author: Albert Krewinkel
4+---
5+
6+Pandoc handles org files very similarly to Emacs org-mode.
7+However, there are differences worth highlighting.
8+
9+
10+Citations
11+=========
12+
13+Emacs org-mode lacks an official citation syntax, leading to
14+multiple syntaxes coexisting. Pandoc recognizes four different
15+syntaxes for citations.
16+
17+Berkeley-style citations
18+------------------------
19+
20+The semi-offical Org-mode citation syntax is based on John
21+MacFarlane's Pandoc syntax and org-oriented enhancements
22+contributed by Richard Lawrence and others. It's dubbed Berkeley
23+syntax due the place of activity of its main contributors.
24+
25+Example:
26+
27+ See @john_doe_2006.
28+ [cite: See; @Mandelkern1981; and @Watson1953]
29+ [(cite): See; @Mandelkern1981; and @Watson1953]
30+
31+
32+org-ref citations
33+-----------------
34+
35+The [org-ref] package is in wide use to handle citations and has
36+excellent tooling support in Emacs. Its citation syntax is
37+geared towards users in the natural sciences but still very
38+flexible regardless.
39+
40+ cite:doe_john_2000
41+ citep:doe_jane_1989
42+ [[citep:Dominik201408][See page 20 of::, for example]]
43+
44+
45+Pandoc-Markdown-like syntax
46+---------------------------
47+
48+Historically, Markdown-style citations syntax was the first that
49+was added to pandoc's org reader. It is almost identical to
50+Markdown's citation syntax.
51+
52+Example:
53+
54+ [prefix @citekey suffix]
55+ [see @doe2000 p. 23-42]
56+
57+
58+LaTeX-Syntax
59+------------
60+
61+Use normal latex citation commands like `\cite{x}` or
62+`\citet{y}`.
63+
64+[org-ref]: https://github.com/jkitchin/org-ref
65+
66+
67+Emphasis rules
68+==============
69+
70+Org-mode uses complex rules to decide whether a string
71+represents emphasized text. In Emacs, this can be customized via
72+the variable `org-emphasis-regexp-components`. A variable like
73+this doesn't fit well with pandoc's model. Instead, it is
74+possible to use special lines to change these values:
75+
76+ #+pandoc-emphasis-pre: "-\t ('\"{"
77+ #+pandoc-emphasis-post: "-\t\n .,:!?;'\")}["
78+
79+The above describes the default values of these variables. The
80+arguments must be valid (Haskell) strings. If interpretation of
81+the argument as string fails, the default is restored.
82+
83+Changing emphasis rules only affect the part of the document
84+following the special lines. They must be some of the first
85+lines to alter parsing behavior for the whole document. It is
86+also possible to change the values temporarily for selected
87+sections only. The string `test` in the following snippet will
88+be read as emphasized text, while the rest of the document will
89+be parsed using default emphasis rules:
90+
91+ #+pandoc-emphasis-pre: "["
92+ #+pandoc-emphasis-post: "]"
93+ [/test/]
94+ #+pandoc-emphasis-pre:
95+ #+pandoc-emphasis-post:
lib/fonts/Makefiledeleted−6
@@ -1,6 +0,0 @@
1−symbol.hs: symbol.txt
2− runghc parseUnicodeMapping.hs symbol.txt
3−
4−.PHONY: clean
5−clean:
6− -rm symbol.hs
lib/fonts/parseUnicodeMapping.hsdeleted−40
@@ -1,40 +0,0 @@
1−import System.FilePath
2−import Text.Parsec
3−import Data.Char
4−import System.Environment
5−import Control.Applicative hiding (many)
6−import Data.List
7−
8−main :: IO ()
9−main = (head <$> getArgs) >>= parseUnicodeMapping
10−
11−
12−parseUnicodeMapping :: FilePath -> IO ()
13−parseUnicodeMapping fname = do
14− fin <- readFile fname
15− let mapname = dropExtension . takeFileName $ fname
16− let res = runParse fin
17− let header = "-- Generated from " ++ fname ++ "\n" ++
18− mapname ++ " :: [(Char, Char)]\n" ++ mapname ++" =\n [ "
19− let footer = "]"
20− writeFile (replaceExtension fname ".hs")
21− (header ++ (concat $ intersperse "\n , " (map show res)) ++ footer)
22−
23−type Unicode = Char
24−
25−runParse :: String -> [(Char, Unicode)]
26−runParse s= either (error . show) id (parse parseMap "" s)
27−
28−anyline = manyTill anyChar newline
29−
30−getHexChar :: Parsec String () Char
31−getHexChar = do
32− [(c,_)] <- readLitChar . ("\\x" ++) <$> many1 hexDigit
33− return c
34−
35−parseMap :: Parsec String () [(Char, Unicode)]
36−parseMap = do
37− skipMany (char '#' >> anyline)
38− many (flip (,) <$> getHexChar <* tab <*> getHexChar <* anyline)
39−
40−
lib/fonts/symbol.txtdeleted−256
@@ -1,256 +0,0 @@
1−#
2−# Name: Adobe Symbol Encoding to Unicode
3−# Unicode version: 2.0
4−# Table version: 1.0
5−# Date: 2011 July 12
6−#
7−# Copyright (c) 1991-2011 Unicode, Inc. All Rights reserved.
8−#
9−# This file is provided as-is by Unicode, Inc. (The Unicode Consortium). No
10−# claims are made as to fitness for any particular purpose. No warranties of
11−# any kind are expressed or implied. The recipient agrees to determine
12−# applicability of information provided. If this file has been provided on
13−# magnetic media by Unicode, Inc., the sole remedy for any claim will be
14−# exchange of defective media within 90 days of receipt.
15−#
16−# Unicode, Inc. hereby grants the right to freely use the information
17−# supplied in this file in the creation of products supporting the
18−# Unicode Standard, and to make copies of this file in any form for
19−# internal or external distribution as long as this notice remains
20−# attached.
21−#
22−# Format: 4 tab-delimited fields:
23−#
24−# (1) The Unicode value (in hexadecimal)
25−# (2) The Symbol Encoding code point (in hexadecimal)
26−# (3) # Unicode name
27−# (4) # PostScript character name
28−#
29−# General Notes:
30−#
31−# The Unicode values in this table were produced as the result of applying
32−# the algorithm described in the section "Populating a Unicode space" in the
33−# document "Unicode and Glyph Names," at
34−# http://partners.adobe.com/asn/developer/typeforum/unicodegn.html
35−# to the characters in Symbol. Note that some characters, such as "space",
36−# are mapped to 2 Unicode values. 29 characters have assignments in the
37−# Corporate Use Subarea; these are indicated by "(CUS)" in field 4. Refer to
38−# the above document for more details.
39−#
40−# 2011 July 12: The above link is no longer valid. For comparable,
41−# more current information, see the document, "Glyph", at:
42−# <http://www.adobe.com/devnet/opentype/archives/glyph.html>
43−#
44−# Revision History:
45−#
46−# [v1.0, 2011 July 12]
47−# Updated terms of use to current wording.
48−# Updated contact information and document link.
49−# No changes to the mapping data.
50−#
51−# [v0.2, 30 March 1999]
52−# Different algorithm to produce Unicode values (see notes above) results in
53−# some character codes being mapped to 2 Unicode values; use of Corporate
54−# Use subarea values; addition of the euro character; changed assignments of
55−# some characters such as the COPYRIGHT SIGNs and RADICAL EXTENDER. Updated
56−# Unicode names to Unicode 2.0 names.
57−#
58−# [v0.1, 5 May 1995] First release.
59−#
60−# Use the Unicode reporting form <http://www.unicode.org/reporting.html>
61−# for any questions or comments or to report errors in the data.
62−#
63−0020 20 # SPACE # space
64−00A0 20 # NO-BREAK SPACE # space
65−0021 21 # EXCLAMATION MARK # exclam
66−2200 22 # FOR ALL # universal
67−0023 23 # NUMBER SIGN # numbersign
68−2203 24 # THERE EXISTS # existential
69−0025 25 # PERCENT SIGN # percent
70−0026 26 # AMPERSAND # ampersand
71−220B 27 # CONTAINS AS MEMBER # suchthat
72−0028 28 # LEFT PARENTHESIS # parenleft
73−0029 29 # RIGHT PARENTHESIS # parenright
74−2217 2A # ASTERISK OPERATOR # asteriskmath
75−002B 2B # PLUS SIGN # plus
76−002C 2C # COMMA # comma
77−2212 2D # MINUS SIGN # minus
78−002E 2E # FULL STOP # period
79−002F 2F # SOLIDUS # slash
80−0030 30 # DIGIT ZERO # zero
81−0031 31 # DIGIT ONE # one
82−0032 32 # DIGIT TWO # two
83−0033 33 # DIGIT THREE # three
84−0034 34 # DIGIT FOUR # four
85−0035 35 # DIGIT FIVE # five
86−0036 36 # DIGIT SIX # six
87−0037 37 # DIGIT SEVEN # seven
88−0038 38 # DIGIT EIGHT # eight
89−0039 39 # DIGIT NINE # nine
90−003A 3A # COLON # colon
91−003B 3B # SEMICOLON # semicolon
92−003C 3C # LESS-THAN SIGN # less
93−003D 3D # EQUALS SIGN # equal
94−003E 3E # GREATER-THAN SIGN # greater
95−003F 3F # QUESTION MARK # question
96−2245 40 # APPROXIMATELY EQUAL TO # congruent
97−0391 41 # GREEK CAPITAL LETTER ALPHA # Alpha
98−0392 42 # GREEK CAPITAL LETTER BETA # Beta
99−03A7 43 # GREEK CAPITAL LETTER CHI # Chi
100−0394 44 # GREEK CAPITAL LETTER DELTA # Delta
101−2206 44 # INCREMENT # Delta
102−0395 45 # GREEK CAPITAL LETTER EPSILON # Epsilon
103−03A6 46 # GREEK CAPITAL LETTER PHI # Phi
104−0393 47 # GREEK CAPITAL LETTER GAMMA # Gamma
105−0397 48 # GREEK CAPITAL LETTER ETA # Eta
106−0399 49 # GREEK CAPITAL LETTER IOTA # Iota
107−03D1 4A # GREEK THETA SYMBOL # theta1
108−039A 4B # GREEK CAPITAL LETTER KAPPA # Kappa
109−039B 4C # GREEK CAPITAL LETTER LAMDA # Lambda
110−039C 4D # GREEK CAPITAL LETTER MU # Mu
111−039D 4E # GREEK CAPITAL LETTER NU # Nu
112−039F 4F # GREEK CAPITAL LETTER OMICRON # Omicron
113−03A0 50 # GREEK CAPITAL LETTER PI # Pi
114−0398 51 # GREEK CAPITAL LETTER THETA # Theta
115−03A1 52 # GREEK CAPITAL LETTER RHO # Rho
116−03A3 53 # GREEK CAPITAL LETTER SIGMA # Sigma
117−03A4 54 # GREEK CAPITAL LETTER TAU # Tau
118−03A5 55 # GREEK CAPITAL LETTER UPSILON # Upsilon
119−03C2 56 # GREEK SMALL LETTER FINAL SIGMA # sigma1
120−03A9 57 # GREEK CAPITAL LETTER OMEGA # Omega
121−2126 57 # OHM SIGN # Omega
122−039E 58 # GREEK CAPITAL LETTER XI # Xi
123−03A8 59 # GREEK CAPITAL LETTER PSI # Psi
124−0396 5A # GREEK CAPITAL LETTER ZETA # Zeta
125−005B 5B # LEFT SQUARE BRACKET # bracketleft
126−2234 5C # THEREFORE # therefore
127−005D 5D # RIGHT SQUARE BRACKET # bracketright
128−22A5 5E # UP TACK # perpendicular
129−005F 5F # LOW LINE # underscore
130−F8E5 60 # RADICAL EXTENDER # radicalex (CUS)
131−03B1 61 # GREEK SMALL LETTER ALPHA # alpha
132−03B2 62 # GREEK SMALL LETTER BETA # beta
133−03C7 63 # GREEK SMALL LETTER CHI # chi
134−03B4 64 # GREEK SMALL LETTER DELTA # delta
135−03B5 65 # GREEK SMALL LETTER EPSILON # epsilon
136−03C6 66 # GREEK SMALL LETTER PHI # phi
137−03B3 67 # GREEK SMALL LETTER GAMMA # gamma
138−03B7 68 # GREEK SMALL LETTER ETA # eta
139−03B9 69 # GREEK SMALL LETTER IOTA # iota
140−03D5 6A # GREEK PHI SYMBOL # phi1
141−03BA 6B # GREEK SMALL LETTER KAPPA # kappa
142−03BB 6C # GREEK SMALL LETTER LAMDA # lambda
143−00B5 6D # MICRO SIGN # mu
144−03BC 6D # GREEK SMALL LETTER MU # mu
145−03BD 6E # GREEK SMALL LETTER NU # nu
146−03BF 6F # GREEK SMALL LETTER OMICRON # omicron
147−03C0 70 # GREEK SMALL LETTER PI # pi
148−03B8 71 # GREEK SMALL LETTER THETA # theta
149−03C1 72 # GREEK SMALL LETTER RHO # rho
150−03C3 73 # GREEK SMALL LETTER SIGMA # sigma
151−03C4 74 # GREEK SMALL LETTER TAU # tau
152−03C5 75 # GREEK SMALL LETTER UPSILON # upsilon
153−03D6 76 # GREEK PI SYMBOL # omega1
154−03C9 77 # GREEK SMALL LETTER OMEGA # omega
155−03BE 78 # GREEK SMALL LETTER XI # xi
156−03C8 79 # GREEK SMALL LETTER PSI # psi
157−03B6 7A # GREEK SMALL LETTER ZETA # zeta
158−007B 7B # LEFT CURLY BRACKET # braceleft
159−007C 7C # VERTICAL LINE # bar
160−007D 7D # RIGHT CURLY BRACKET # braceright
161−223C 7E # TILDE OPERATOR # similar
162−20AC A0 # EURO SIGN # Euro
163−03D2 A1 # GREEK UPSILON WITH HOOK SYMBOL # Upsilon1
164−2032 A2 # PRIME # minute
165−2264 A3 # LESS-THAN OR EQUAL TO # lessequal
166−2044 A4 # FRACTION SLASH # fraction
167−2215 A4 # DIVISION SLASH # fraction
168−221E A5 # INFINITY # infinity
169−0192 A6 # LATIN SMALL LETTER F WITH HOOK # florin
170−2663 A7 # BLACK CLUB SUIT # club
171−2666 A8 # BLACK DIAMOND SUIT # diamond
172−2665 A9 # BLACK HEART SUIT # heart
173−2660 AA # BLACK SPADE SUIT # spade
174−2194 AB # LEFT RIGHT ARROW # arrowboth
175−2190 AC # LEFTWARDS ARROW # arrowleft
176−2191 AD # UPWARDS ARROW # arrowup
177−2192 AE # RIGHTWARDS ARROW # arrowright
178−2193 AF # DOWNWARDS ARROW # arrowdown
179−00B0 B0 # DEGREE SIGN # degree
180−00B1 B1 # PLUS-MINUS SIGN # plusminus
181−2033 B2 # DOUBLE PRIME # second
182−2265 B3 # GREATER-THAN OR EQUAL TO # greaterequal
183−00D7 B4 # MULTIPLICATION SIGN # multiply
184−221D B5 # PROPORTIONAL TO # proportional
185−2202 B6 # PARTIAL DIFFERENTIAL # partialdiff
186−2022 B7 # BULLET # bullet
187−00F7 B8 # DIVISION SIGN # divide
188−2260 B9 # NOT EQUAL TO # notequal
189−2261 BA # IDENTICAL TO # equivalence
190−2248 BB # ALMOST EQUAL TO # approxequal
191−2026 BC # HORIZONTAL ELLIPSIS # ellipsis
192−F8E6 BD # VERTICAL ARROW EXTENDER # arrowvertex (CUS)
193−F8E7 BE # HORIZONTAL ARROW EXTENDER # arrowhorizex (CUS)
194−21B5 BF # DOWNWARDS ARROW WITH CORNER LEFTWARDS # carriagereturn
195−2135 C0 # ALEF SYMBOL # aleph
196−2111 C1 # BLACK-LETTER CAPITAL I # Ifraktur
197−211C C2 # BLACK-LETTER CAPITAL R # Rfraktur
198−2118 C3 # SCRIPT CAPITAL P # weierstrass
199−2297 C4 # CIRCLED TIMES # circlemultiply
200−2295 C5 # CIRCLED PLUS # circleplus
201−2205 C6 # EMPTY SET # emptyset
202−2229 C7 # INTERSECTION # intersection
203−222A C8 # UNION # union
204−2283 C9 # SUPERSET OF # propersuperset
205−2287 CA # SUPERSET OF OR EQUAL TO # reflexsuperset
206−2284 CB # NOT A SUBSET OF # notsubset
207−2282 CC # SUBSET OF # propersubset
208−2286 CD # SUBSET OF OR EQUAL TO # reflexsubset
209−2208 CE # ELEMENT OF # element
210−2209 CF # NOT AN ELEMENT OF # notelement
211−2220 D0 # ANGLE # angle
212−2207 D1 # NABLA # gradient
213−F6DA D2 # REGISTERED SIGN SERIF # registerserif (CUS)
214−F6D9 D3 # COPYRIGHT SIGN SERIF # copyrightserif (CUS)
215−F6DB D4 # TRADE MARK SIGN SERIF # trademarkserif (CUS)
216−220F D5 # N-ARY PRODUCT # product
217−221A D6 # SQUARE ROOT # radical
218−22C5 D7 # DOT OPERATOR # dotmath
219−00AC D8 # NOT SIGN # logicalnot
220−2227 D9 # LOGICAL AND # logicaland
221−2228 DA # LOGICAL OR # logicalor
222−21D4 DB # LEFT RIGHT DOUBLE ARROW # arrowdblboth
223−21D0 DC # LEFTWARDS DOUBLE ARROW # arrowdblleft
224−21D1 DD # UPWARDS DOUBLE ARROW # arrowdblup
225−21D2 DE # RIGHTWARDS DOUBLE ARROW # arrowdblright
226−21D3 DF # DOWNWARDS DOUBLE ARROW # arrowdbldown
227−25CA E0 # LOZENGE # lozenge
228−2329 E1 # LEFT-POINTING ANGLE BRACKET # angleleft
229−F8E8 E2 # REGISTERED SIGN SANS SERIF # registersans (CUS)
230−F8E9 E3 # COPYRIGHT SIGN SANS SERIF # copyrightsans (CUS)
231−F8EA E4 # TRADE MARK SIGN SANS SERIF # trademarksans (CUS)
232−2211 E5 # N-ARY SUMMATION # summation
233−F8EB E6 # LEFT PAREN TOP # parenlefttp (CUS)
234−F8EC E7 # LEFT PAREN EXTENDER # parenleftex (CUS)
235−F8ED E8 # LEFT PAREN BOTTOM # parenleftbt (CUS)
236−F8EE E9 # LEFT SQUARE BRACKET TOP # bracketlefttp (CUS)
237−F8EF EA # LEFT SQUARE BRACKET EXTENDER # bracketleftex (CUS)
238−F8F0 EB # LEFT SQUARE BRACKET BOTTOM # bracketleftbt (CUS)
239−F8F1 EC # LEFT CURLY BRACKET TOP # bracelefttp (CUS)
240−F8F2 ED # LEFT CURLY BRACKET MID # braceleftmid (CUS)
241−F8F3 EE # LEFT CURLY BRACKET BOTTOM # braceleftbt (CUS)
242−F8F4 EF # CURLY BRACKET EXTENDER # braceex (CUS)
243−232A F1 # RIGHT-POINTING ANGLE BRACKET # angleright
244−222B F2 # INTEGRAL # integral
245−2320 F3 # TOP HALF INTEGRAL # integraltp
246−F8F5 F4 # INTEGRAL EXTENDER # integralex (CUS)
247−2321 F5 # BOTTOM HALF INTEGRAL # integralbt
248−F8F6 F6 # RIGHT PAREN TOP # parenrighttp (CUS)
249−F8F7 F7 # RIGHT PAREN EXTENDER # parenrightex (CUS)
250−F8F8 F8 # RIGHT PAREN BOTTOM # parenrightbt (CUS)
251−F8F9 F9 # RIGHT SQUARE BRACKET TOP # bracketrighttp (CUS)
252−F8FA FA # RIGHT SQUARE BRACKET EXTENDER # bracketrightex (CUS)
253−F8FB FB # RIGHT SQUARE BRACKET BOTTOM # bracketrightbt (CUS)
254−F8FC FC # RIGHT CURLY BRACKET TOP # bracerighttp (CUS)
255−F8FD FD # RIGHT CURLY BRACKET MID # bracerightmid (CUS)
256−F8FE FE # RIGHT CURLY BRACKET BOTTOM # bracerightbt (CUS)
linux/Dockerfile+12−5
@@ -1,18 +1,25 @@
11# USE ALPINE LINUX
2−FROM alpine:edge
2+FROM alpine
3+RUN apk update
4+# INSTALL BASIC DEV TOOLS, GHC, GMP & ZLIB
35RUN echo "https://s3-us-west-2.amazonaws.com/alpine-ghc/8.0" >> /etc/apk/repositories
46ADD https://raw.githubusercontent.com/mitchty/alpine-ghc/master/mitch.tishmack%40gmail.com-55881c97.rsa.pub \
57 /etc/apk/keys/mitch.tishmack@gmail.com-55881c97.rsa.pub
68RUN apk update
7−RUN apk add alpine-sdk git ca-certificates ghc cabal stack zlib-dev \
8− dpkg fakeroot sed gawk grep bash linux-headers
9−RUN stack update
9+RUN apk add alpine-sdk git ca-certificates ghc gmp-dev zlib-dev bash dpkg fakeroot
10+# GRAB A RECENT BINARY OF STACK
11+RUN curl -L https://www.stackage.org/stack/linux-x86_64-static | tar xz --wildcards --strip-components=1 -C /usr/local/bin '*/stack'
12+# COMPRESS WITH UPX
13+ADD https://github.com/lalyos/docker-upx/releases/download/v3.91/upx /usr/local/bin/upx
14+RUN chmod 755 /usr/local/bin/upx
15+RUN ulimit -n 4096
1016RUN stack config set system-ghc --global true
17+RUN stack --resolver lts-9 setup --install-cabal 2.0.1.1
1118#RUN mkdir -p /etc/stack
1219#RUN echo "build: { split-objs: true }" > /etc/stack/config.yaml
1320RUN mkdir -p /usr/src/
1421WORKDIR /usr/src/
15−RUN git clone https://github.com/jgm/pandoc
22+RUN git clone https://github.com/jgm/pandoc
1623WORKDIR /usr/src/pandoc
1724RUN stack install --stack-yaml stack.lts9.yaml \
1825 --only-dependencies \
man/pandoc.1+426−154
@@ -1,5 +1,5 @@
11.\"t
2−.TH PANDOC 1 "January 18, 2018" "pandoc 2.1.1"
2+.TH PANDOC 1 "April 26, 2018" "pandoc 2.2"
33.SH NAME
44pandoc - general markup converter
55.SH SYNOPSIS
@@ -10,34 +10,21 @@ pandoc - general markup converter
1010Pandoc is a Haskell library for converting from one markup format to
1111another, and a command\-line tool that uses this library.
1212.PP
13−Pandoc can read Markdown, CommonMark, PHP Markdown Extra,
14−GitHub\-Flavored Markdown, MultiMarkdown, and (subsets of) Textile,
15−reStructuredText, HTML, LaTeX, MediaWiki markup, TWiki markup, TikiWiki
16−markup, Creole 1.0, Haddock markup, OPML, Emacs Org mode, DocBook, JATS,
17−Muse, txt2tags, Vimwiki, EPUB, ODT, and Word docx.
18−.PP
19−Pandoc can write plain text, Markdown, CommonMark, PHP Markdown Extra,
20−GitHub\-Flavored Markdown, MultiMarkdown, reStructuredText, XHTML,
21−HTML5, LaTeX (including \f[C]beamer\f[] slide shows), ConTeXt, RTF,
22−OPML, DocBook, JATS, OpenDocument, ODT, Word docx, GNU Texinfo,
23−MediaWiki markup, DokuWiki markup, ZimWiki markup, Haddock markup, EPUB
24−(v2 or v3), FictionBook2, Textile, groff man, groff ms, Emacs Org mode,
25−AsciiDoc, InDesign ICML, TEI Simple, Muse, PowerPoint slide shows and
26−Slidy, Slideous, DZSlides, reveal.js or S5 HTML slide shows.
27−It can also produce PDF output on systems where LaTeX, ConTeXt,
28−\f[C]pdfroff\f[], \f[C]wkhtmltopdf\f[], \f[C]prince\f[], or
29−\f[C]weasyprint\f[] is installed.
13+Pandoc can convert between numerous markup and word processing formats,
14+including, but not limited to, various flavors of Markdown, HTML, LaTeX
15+and Word docx.
16+For the full lists of input and output formats, see the
17+\f[C]\-\-from\f[] and \f[C]\-\-to\f[] options below.
18+Pandoc can also produce PDF output: see creating a PDF, below.
3019.PP
3120Pandoc\[aq]s enhanced version of Markdown includes syntax for tables,
32−definition lists, metadata blocks, \f[C]Div\f[] blocks, footnotes and
33−citations, embedded LaTeX (including math), Markdown inside HTML block
34−elements, and much more.
35−These enhancements, described further under Pandoc\[aq]s Markdown, can
36−be disabled using the \f[C]markdown_strict\f[] format.
21+definition lists, metadata blocks, footnotes, citations, math, and much
22+more.
23+See below under Pandoc\[aq]s Markdown.
3724.PP
3825Pandoc has a modular design: it consists of a set of readers, which
3926parse text in a given format and produce a native representation of the
40−document (like an \f[I]abstract syntax tree\f[] or AST), and a set of
27+document (an \f[I]abstract syntax tree\f[] or AST), and a set of
4128writers, which convert this native representation into a target format.
4229Thus, adding an input or output format requires only adding a reader or
4330writer.
@@ -175,7 +162,8 @@ When using an HTML/CSS\-to\-PDF\-engine, \f[C]\-\-css\f[] affects the
175162output.
176163If \f[C]wkhtmltopdf\f[] is used, then the variables
177164\f[C]margin\-left\f[], \f[C]margin\-right\f[], \f[C]margin\-top\f[],
178−\f[C]margin\-bottom\f[], and \f[C]papersize\f[] will affect the output.
165+\f[C]margin\-bottom\f[], \f[C]footer\-html\f[], \f[C]header\-html\f[]
166+and \f[C]papersize\f[] will affect the output.
179167.PP
180168To debug the PDF creation, it can be useful to look at the intermediate
181169representation: instead of \f[C]\-o\ test.pdf\f[], use for example
@@ -228,69 +216,184 @@ pandoc\ \-f\ html\ \-t\ markdown\ \-\-request\-header\ User\-Agent:"Mozilla/5.0"
228216.TP
229217.B \f[C]\-f\f[] \f[I]FORMAT\f[], \f[C]\-r\f[] \f[I]FORMAT\f[], \f[C]\-\-from=\f[]\f[I]FORMAT\f[], \f[C]\-\-read=\f[]\f[I]FORMAT\f[]
230218Specify input format.
231−\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
232−(JSON version of native AST), \f[C]markdown\f[] (pandoc\[aq]s extended
233−Markdown), \f[C]markdown_strict\f[] (original unextended Markdown),
234−\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[]
235−(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown),
236−\f[C]commonmark\f[] (CommonMark Markdown), \f[C]textile\f[] (Textile),
237−\f[C]rst\f[] (reStructuredText), \f[C]html\f[] (HTML), \f[C]docbook\f[]
238−(DocBook), \f[C]t2t\f[] (txt2tags), \f[C]docx\f[] (docx), \f[C]odt\f[]
239−(ODT), \f[C]epub\f[] (EPUB), \f[C]opml\f[] (OPML), \f[C]org\f[] (Emacs
240−Org mode), \f[C]mediawiki\f[] (MediaWiki markup), \f[C]twiki\f[] (TWiki
241−markup), \f[C]tikiwiki\f[] (TikiWiki markup), \f[C]creole\f[] (Creole
242−1.0), \f[C]haddock\f[] (Haddock markup), or \f[C]latex\f[] (LaTeX).
243−(\f[C]markdown_github\f[] provides deprecated and less accurate support
244−for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless
245−you need to use extensions other than \f[C]smart\f[].) Extensions can be
246−individually enabled or disabled by appending \f[C]+EXTENSION\f[] or
247−\f[C]\-EXTENSION\f[] to the format name.
219+\f[I]FORMAT\f[] can be:
220+.RS
221+.IP \[bu] 2
222+\f[C]commonmark\f[] (CommonMark Markdown)
223+.IP \[bu] 2
224+\f[C]creole\f[] (Creole 1.0)
225+.IP \[bu] 2
226+\f[C]docbook\f[] (DocBook)
227+.IP \[bu] 2
228+\f[C]docx\f[] (Word docx)
229+.IP \[bu] 2
230+\f[C]epub\f[] (EPUB)
231+.IP \[bu] 2
232+\f[C]fb2\f[] (FictionBook2 e\-book)
233+.IP \[bu] 2
234+\f[C]gfm\f[] (GitHub\-Flavored Markdown), or \f[C]markdown_github\f[],
235+which provides deprecated and less accurate support for Github\-Flavored
236+Markdown; please use \f[C]gfm\f[] instead, unless you need to use
237+extensions other than \f[C]smart\f[].
238+.IP \[bu] 2
239+\f[C]haddock\f[] (Haddock markup)
240+.IP \[bu] 2
241+\f[C]html\f[] (HTML)
242+.IP \[bu] 2
243+\f[C]jats\f[] (JATS XML)
244+.IP \[bu] 2
245+\f[C]json\f[] (JSON version of native AST)
246+.IP \[bu] 2
247+\f[C]latex\f[] (LaTeX)
248+.IP \[bu] 2
249+\f[C]markdown\f[] (Pandoc\[aq]s Markdown)
250+.IP \[bu] 2
251+\f[C]markdown_mmd\f[] (MultiMarkdown)
252+.IP \[bu] 2
253+\f[C]markdown_phpextra\f[] (PHP Markdown Extra)
254+.IP \[bu] 2
255+\f[C]markdown_strict\f[] (original unextended Markdown)
256+.IP \[bu] 2
257+\f[C]mediawiki\f[] (MediaWiki markup)
258+.IP \[bu] 2
259+\f[C]muse\f[] (Muse)
260+.IP \[bu] 2
261+\f[C]native\f[] (native Haskell)
262+.IP \[bu] 2
263+\f[C]odt\f[] (ODT)
264+.IP \[bu] 2
265+\f[C]opml\f[] (OPML)
266+.IP \[bu] 2
267+\f[C]org\f[] (Emacs Org mode)
268+.IP \[bu] 2
269+\f[C]rst\f[] (reStructuredText)
270+.IP \[bu] 2
271+\f[C]t2t\f[] (txt2tags)
272+.IP \[bu] 2
273+\f[C]textile\f[] (Textile)
274+.IP \[bu] 2
275+\f[C]tikiwiki\f[] (TikiWiki markup)
276+.IP \[bu] 2
277+\f[C]twiki\f[] (TWiki markup)
278+.IP \[bu] 2
279+\f[C]vimwiki\f[] (Vimwiki)
280+.PP
281+Extensions can be individually enabled or disabled by appending
282+\f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name.
248283See Extensions below, for a list of extensions and their names.
249284See \f[C]\-\-list\-input\-formats\f[] and \f[C]\-\-list\-extensions\f[],
250285below.
251−.RS
252286.RE
253287.TP
254288.B \f[C]\-t\f[] \f[I]FORMAT\f[], \f[C]\-w\f[] \f[I]FORMAT\f[], \f[C]\-\-to=\f[]\f[I]FORMAT\f[], \f[C]\-\-write=\f[]\f[I]FORMAT\f[]
255289Specify output format.
256−\f[I]FORMAT\f[] can be \f[C]native\f[] (native Haskell), \f[C]json\f[]
257−(JSON version of native AST), \f[C]plain\f[] (plain text),
258−\f[C]markdown\f[] (pandoc\[aq]s extended Markdown),
259−\f[C]markdown_strict\f[] (original unextended Markdown),
260−\f[C]markdown_phpextra\f[] (PHP Markdown Extra), \f[C]markdown_mmd\f[]
261−(MultiMarkdown), \f[C]gfm\f[] (GitHub\-Flavored Markdown),
262−\f[C]commonmark\f[] (CommonMark Markdown), \f[C]rst\f[]
263−(reStructuredText), \f[C]html4\f[] (XHTML 1.0 Transitional),
264−\f[C]html\f[] or \f[C]html5\f[] (HTML5/XHTML polyglot markup),
265−\f[C]latex\f[] (LaTeX), \f[C]beamer\f[] (LaTeX beamer slide show),
266−\f[C]context\f[] (ConTeXt), \f[C]man\f[] (groff man), \f[C]mediawiki\f[]
267−(MediaWiki markup), \f[C]dokuwiki\f[] (DokuWiki markup),
268−\f[C]zimwiki\f[] (ZimWiki markup), \f[C]textile\f[] (Textile),
269−\f[C]org\f[] (Emacs Org mode), \f[C]texinfo\f[] (GNU Texinfo),
270−\f[C]opml\f[] (OPML), \f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4),
271−\f[C]docbook5\f[] (DocBook 5), \f[C]jats\f[] (JATS XML),
272−\f[C]opendocument\f[] (OpenDocument), \f[C]odt\f[] (OpenOffice text
273−document), \f[C]docx\f[] (Word docx), \f[C]haddock\f[] (Haddock markup),
274−\f[C]rtf\f[] (rich text format), \f[C]epub2\f[] (EPUB v2 book),
275−\f[C]epub\f[] or \f[C]epub3\f[] (EPUB v3), \f[C]fb2\f[] (FictionBook2
276−e\-book), \f[C]asciidoc\f[] (AsciiDoc), \f[C]icml\f[] (InDesign ICML),
277−\f[C]tei\f[] (TEI Simple), \f[C]slidy\f[] (Slidy HTML and JavaScript
278−slide show), \f[C]slideous\f[] (Slideous HTML and JavaScript slide
279−show), \f[C]dzslides\f[] (DZSlides HTML5 + JavaScript slide show),
280−\f[C]revealjs\f[] (reveal.js HTML5 + JavaScript slide show), \f[C]s5\f[]
281−(S5 HTML and JavaScript slide show), \f[C]pptx\f[] (PowerPoint slide
282−show) or the path of a custom lua writer (see Custom writers, below).
283−(\f[C]markdown_github\f[] provides deprecated and less accurate support
284−for Github\-Flavored Markdown; please use \f[C]gfm\f[] instead, unless
285−you use extensions that do not work with \f[C]gfm\f[].) Note that
286−\f[C]odt\f[], \f[C]docx\f[], and \f[C]epub\f[] output will not be
287−directed to \f[I]stdout\f[] unless forced with \f[C]\-o\ \-\f[].
290+\f[I]FORMAT\f[] can be:
291+.RS
292+.IP \[bu] 2
293+\f[C]asciidoc\f[] (AsciiDoc)
294+.IP \[bu] 2
295+\f[C]beamer\f[] (LaTeX beamer slide show)
296+.IP \[bu] 2
297+\f[C]commonmark\f[] (CommonMark Markdown)
298+.IP \[bu] 2
299+\f[C]context\f[] (ConTeXt)
300+.IP \[bu] 2
301+\f[C]docbook\f[] or \f[C]docbook4\f[] (DocBook 4)
302+.IP \[bu] 2
303+\f[C]docbook5\f[] (DocBook 5)
304+.IP \[bu] 2
305+\f[C]docx\f[] (Word docx)
306+.IP \[bu] 2
307+\f[C]dokuwiki\f[] (DokuWiki markup)
308+.IP \[bu] 2
309+\f[C]epub\f[] or \f[C]epub3\f[] (EPUB v3 book)
310+.IP \[bu] 2
311+\f[C]epub2\f[] (EPUB v2)
312+.IP \[bu] 2
313+\f[C]fb2\f[] (FictionBook2 e\-book)
314+.IP \[bu] 2
315+\f[C]gfm\f[] (GitHub\-Flavored Markdown), or \f[C]markdown_github\f[],
316+which provides deprecated and less accurate support for Github\-Flavored
317+Markdown; please use \f[C]gfm\f[] instead, unless you use extensions
318+that do not work with \f[C]gfm\f[].
319+.IP \[bu] 2
320+\f[C]haddock\f[] (Haddock markup)
321+.IP \[bu] 2
322+\f[C]html\f[] or \f[C]html5\f[] (HTML, i.e.
323+HTML5/XHTML polyglot markup)
324+.IP \[bu] 2
325+\f[C]html4\f[] (XHTML 1.0 Transitional)
326+.IP \[bu] 2
327+\f[C]icml\f[] (InDesign ICML)
328+.IP \[bu] 2
329+\f[C]jats\f[] (JATS XML)
330+.IP \[bu] 2
331+\f[C]json\f[] (JSON version of native AST)
332+.IP \[bu] 2
333+\f[C]latex\f[] (LaTeX)
334+.IP \[bu] 2
335+\f[C]man\f[] (groff man)
336+.IP \[bu] 2
337+\f[C]markdown\f[] (Pandoc\[aq]s Markdown)
338+.IP \[bu] 2
339+\f[C]markdown_mmd\f[] (MultiMarkdown)
340+.IP \[bu] 2
341+\f[C]markdown_phpextra\f[] (PHP Markdown Extra)
342+.IP \[bu] 2
343+\f[C]markdown_strict\f[] (original unextended Markdown)
344+.IP \[bu] 2
345+\f[C]mediawiki\f[] (MediaWiki markup)
346+.IP \[bu] 2
347+\f[C]ms\f[] (groff ms)
348+.IP \[bu] 2
349+\f[C]muse\f[] (Muse),
350+.IP \[bu] 2
351+\f[C]native\f[] (native Haskell),
352+.IP \[bu] 2
353+\f[C]odt\f[] (OpenOffice text document)
354+.IP \[bu] 2
355+\f[C]opml\f[] (OPML)
356+.IP \[bu] 2
357+\f[C]opendocument\f[] (OpenDocument)
358+.IP \[bu] 2
359+\f[C]org\f[] (Emacs Org mode)
360+.IP \[bu] 2
361+\f[C]plain\f[] (plain text),
362+.IP \[bu] 2
363+\f[C]pptx\f[] (PowerPoint slide show)
364+.IP \[bu] 2
365+\f[C]rst\f[] (reStructuredText)
366+.IP \[bu] 2
367+\f[C]rtf\f[] (Rich Text Format)
368+.IP \[bu] 2
369+\f[C]texinfo\f[] (GNU Texinfo)
370+.IP \[bu] 2
371+\f[C]textile\f[] (Textile)
372+.IP \[bu] 2
373+\f[C]slideous\f[] (Slideous HTML and JavaScript slide show)
374+.IP \[bu] 2
375+\f[C]slidy\f[] (Slidy HTML and JavaScript slide show)
376+.IP \[bu] 2
377+\f[C]dzslides\f[] (DZSlides HTML5 + JavaScript slide show),
378+.IP \[bu] 2
379+\f[C]revealjs\f[] (reveal.js HTML5 + JavaScript slide show)
380+.IP \[bu] 2
381+\f[C]s5\f[] (S5 HTML and JavaScript slide show)
382+.IP \[bu] 2
383+\f[C]tei\f[] (TEI Simple)
384+.IP \[bu] 2
385+\f[C]zimwiki\f[] (ZimWiki markup)
386+.IP \[bu] 2
387+the path of a custom lua writer, see Custom writers below
388+.PP
389+Note that \f[C]odt\f[], \f[C]docx\f[], and \f[C]epub\f[] output will not
390+be directed to \f[I]stdout\f[] unless forced with \f[C]\-o\ \-\f[].
391+.PP
288392Extensions can be individually enabled or disabled by appending
289393\f[C]+EXTENSION\f[] or \f[C]\-EXTENSION\f[] to the format name.
290394See Extensions below, for a list of extensions and their names.
291395See \f[C]\-\-list\-output\-formats\f[] and
292396\f[C]\-\-list\-extensions\f[], below.
293−.RS
294397.RE
295398.TP
296399.B \f[C]\-o\f[] \f[I]FILE\f[], \f[C]\-\-output=\f[]\f[I]FILE\f[]
@@ -531,19 +634,29 @@ end
531634return\ {{Str\ =\ expand_hello_world}}
532635\f[]
533636.fi
637+.PP
638+In order of preference, pandoc will look for lua filters in
639+.IP "1." 3
640+a specified full or relative path (executable or non\-executable)
641+.IP "2." 3
642+\f[C]$DATADIR/filters\f[] (executable or non\-executable) where
643+\f[C]$DATADIR\f[] is the user data directory (see
644+\f[C]\-\-data\-dir\f[], above).
534645.RE
535646.TP
536647.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[]]
537648Set the metadata field \f[I]KEY\f[] to the value \f[I]VAL\f[].
538649A value specified on the command line overrides a value specified in the
539−document.
650+document using [YAML metadata
651+blocks][Extension:\f[C]yaml_metadata_block\f[]].
540652Values will be parsed as YAML boolean or string values.
541653If no value is specified, the value will be treated as Boolean true.
542654Like \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] causes template
543655variables to be set.
544656But unlike \f[C]\-\-variable\f[], \f[C]\-\-metadata\f[] affects the
545657metadata of the underlying document (which is accessible from filters
546−and may be printed in some output formats).
658+and may be printed in some output formats) and metadata values will be
659+escaped when inserted into the template.
547660.RS
548661.RE
549662.TP
@@ -821,6 +934,7 @@ line, or when resources used in a document must be downloaded).
821934Produce a standalone HTML file with no external dependencies, using
822935\f[C]data:\f[] URIs to incorporate the contents of linked scripts,
823936stylesheets, images, and videos.
937+Implies \f[C]\-\-standalone\f[].
824938The resulting file should be "self\-contained," in the sense that it
825939needs no external files and no net access to be displayed properly by a
826940browser.
@@ -850,8 +964,9 @@ Use \f[C]<q>\f[] tags for quotes in HTML.
850964.TP
851965.B \f[C]\-\-ascii\f[]
852966Use only ASCII characters in output.
853−Currently supported only for HTML and DocBook output (which uses
854−numerical entities instead of UTF\-8 when this option is selected).
967+Currently supported for XML and HTML formats (which use numerical
968+entities instead of UTF\-8 when this option is selected) and for groff
969+ms and man (which use hexadecimal escapes).
855970.RS
856971.RE
857972.TP
@@ -1044,6 +1159,34 @@ default \f[C]reference.odt\f[]:
10441159Then open \f[C]custom\-reference.odt\f[] in LibreOffice, modify the
10451160styles as you wish, and save the file.
10461161.RE
1162+.TP
1163+.B PowerPoint
1164+Any template included with a recent install of Microsoft PowerPoint
1165+(either with \f[C]\&.pptx\f[] or \f[C]\&.potx\f[] extension) should
1166+work, as will most templates derived from these.
1167+.RS
1168+.PP
1169+The specific requirement is that the template should contain the
1170+following four layouts as its first four layouts:
1171+.IP "1." 3
1172+Title Slide
1173+.IP "2." 3
1174+Title and Content
1175+.IP "3." 3
1176+Section Header
1177+.IP "4." 3
1178+Two Content
1179+.PP
1180+All templates included with a recent version of MS PowerPoint will fit
1181+these criteria.
1182+(You can click on \f[C]Layout\f[] under the \f[C]Home\f[] menu to
1183+check.)
1184+.PP
1185+You can also modify the default \f[C]reference.pptx\f[]: first run
1186+\f[C]pandoc\ \-\-print\-default\-data\-file\ reference.pptx\ >\ custom\-reference.pptx\f[],
1187+and then modify \f[C]custom\-reference.pptx\f[] in MS PowerPoint (pandoc
1188+will use the first four layout slides, as mentioned above).
1189+.RE
10471190.RE
10481191.TP
10491192.B \f[C]\-\-epub\-cover\-image=\f[]\f[I]FILE\f[]
@@ -1270,60 +1413,6 @@ inserted.
12701413Note that this option does not imply \f[C]\-\-katex\f[].
12711414.RS
12721415.RE
1273−.TP
1274−.B \f[C]\-m\f[] [\f[I]URL\f[]], \f[C]\-\-latexmathml\f[][\f[C]=\f[]\f[I]URL\f[]]
1275−\f[I]Deprecated.\f[] Use the LaTeXMathML script to display embedded TeX
1276−math in HTML output.
1277−TeX math will be displayed between \f[C]$\f[] or \f[C]$$\f[] characters
1278−and put in \f[C]<span>\f[] tags with class \f[C]LaTeX\f[].
1279−The LaTeXMathML JavaScript will then change it to MathML.
1280−Note that currently only Firefox and Safari (and select e\-book readers)
1281−natively support MathML.
1282−To insert a link the \f[C]LaTeXMathML.js\f[] script, provide a
1283−\f[I]URL\f[].
1284−.RS
1285−.RE
1286−.TP
1287−.B \f[C]\-\-jsmath\f[][\f[C]=\f[]\f[I]URL\f[]]
1288−\f[I]Deprecated.\f[] Use jsMath (the predecessor of MathJax) to display
1289−embedded TeX math in HTML output.
1290−TeX math will be put inside \f[C]<span>\f[] tags (for inline math) or
1291−\f[C]<div>\f[] tags (for display math) with class \f[C]math\f[] and
1292−rendered by the jsMath script.
1293−The \f[I]URL\f[] should point to the script (e.g.
1294−\f[C]jsMath/easy/load.js\f[]); if provided, it will be linked to in the
1295−header of standalone HTML documents.
1296−If a \f[I]URL\f[] is not provided, no link to the jsMath load script
1297−will be inserted; it is then up to the author to provide such a link in
1298−the HTML template.
1299−.RS
1300−.RE
1301−.TP
1302−.B \f[C]\-\-gladtex\f[]
1303−\f[I]Deprecated.\f[] Enclose TeX math in \f[C]<eq>\f[] tags in HTML
1304−output.
1305−The resulting HTML can then be processed by gladTeX to produce images of
1306−the typeset formulas and an HTML file with links to these images.
1307−So, the procedure is:
1308−.RS
1309−.IP
1310−.nf
1311−\f[C]
1312−pandoc\ \-s\ \-\-gladtex\ input.md\ \-o\ myfile.htex
1313−gladtex\ \-d\ myfile\-images\ myfile.htex
1314−#\ produces\ myfile.html\ and\ images\ in\ myfile\-images
1315−\f[]
1316−.fi
1317−.RE
1318−.TP
1319−.B \f[C]\-\-mimetex\f[][\f[C]=\f[]\f[I]URL\f[]]
1320−\f[I]Deprecated.\f[] Render TeX math using the mimeTeX CGI script, which
1321−generates an image for each TeX formula.
1322−This should work in all browsers.
1323−If \f[I]URL\f[] is not specified, it is assumed that the script is at
1324−\f[C]/cgi\-bin/mimetex.cgi\f[].
1325−.RS
1326−.RE
13271416.SS Options for wrapper scripts
13281417.TP
13291418.B \f[C]\-\-dump\-args\f[]
@@ -1389,23 +1478,25 @@ template.
13891478For \f[C]pdf\f[] output, customize the \f[C]default.latex\f[] template
13901479(or the \f[C]default.context\f[] template, if you use
13911480\f[C]\-t\ context\f[], or the \f[C]default.ms\f[] template, if you use
1392−\f[C]\-t\ ms\f[], or the \f[C]default.html5\f[] template, if you use
1393−\f[C]\-t\ html5\f[]).
1481+\f[C]\-t\ ms\f[], or the \f[C]default.html\f[] template, if you use
1482+\f[C]\-t\ html\f[]).
13941483.IP \[bu] 2
13951484\f[C]docx\f[] has no template (however, you can use
13961485\f[C]\-\-reference\-doc\f[] to customize the output).
13971486.PP
13981487Templates contain \f[I]variables\f[], which allow for the inclusion of
13991488arbitrary information at any point in the file.
1400−Variables may be set within the document using YAML metadata blocks.
1401−They may also be set at the command line using the
1402−\f[C]\-V/\-\-variable\f[] option: variables set in this way override
1403−metadata fields with the same name.
1489+They may be set at the command line using the \f[C]\-V/\-\-variable\f[]
1490+option.
1491+If a variable is not set, pandoc will look for the key in the
1492+document\[aq]s metadata \[en] which can be set using either [YAML
1493+metadata blocks][Extension:\f[C]yaml_metadata_block\f[]] or with the
1494+\f[C]\-\-metadata\f[] option.
14041495.SS Variables set by pandoc
14051496.PP
14061497Some variables are set automatically by pandoc.
1407−These vary somewhat depending on the output format, but include metadata
1408−fields as well as the following:
1498+These vary somewhat depending on the output format, but include the
1499+following:
14091500.TP
14101501.B \f[C]sourcefile\f[], \f[C]outputfile\f[]
14111502source and destination filenames, as given on the command line.
@@ -1648,6 +1739,11 @@ option for document class, e.g.
16481739.RS
16491740.RE
16501741.TP
1742+.B \f[C]beameroption\f[]
1743+In beamer, add extra beamer option with \f[C]\\setbeameroption{}\f[]
1744+.RS
1745+.RE
1746+.TP
16511747.B \f[C]geometry\f[]
16521748option for \f[C]geometry\f[] package, e.g.
16531749\f[C]margin=1in\f[]; may be repeated for multiple options
@@ -1891,6 +1987,16 @@ include table of contents (can also be set using
18911987include list of figures, list of tables
18921988.RS
18931989.RE
1990+.TP
1991+.B \f[C]pdfa\f[]
1992+adds to the preamble the setup necessary to generate PDF/A\-1b:2005.
1993+To successfully generate PDF/A the required ICC color profiles have to
1994+be available and the content and all included files (such as images)
1995+have to be standard conforming.
1996+The ICC profiles can be obtained from ConTeXt ICC Profiles.
1997+See also ConTeXt PDFA for more details.
1998+.RS
1999+.RE
18942000.SS Variables for man pages
18952001.TP
18962002.B \f[C]section\f[]
@@ -2319,7 +2425,7 @@ pandoc\ \-f\ markdown+lhs\ \-t\ html+lhs
23192425writes HTML with the Haskell code in bird tracks, so it can be copied
23202426and pasted as literate Haskell source.
23212427.PP
2322−Note that GHC expects the bird tracks in the first column, so indentend
2428+Note that GHC expects the bird tracks in the first column, so indented
23232429literate code blocks (e.g.
23242430inside an itemized environment) will not be picked up by the Haskell
23252431compiler.
@@ -2337,8 +2443,19 @@ This extension can be enabled/disabled for the following formats:
23372443.RE
23382444.TP
23392445.B output formats
2340−\f[C]markdown\f[], \f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[],
2341−\f[C]html\f[]
2446+\f[C]docx\f[], \f[C]odt\f[], \f[C]opendocument\f[], \f[C]html\f[]
2447+.RS
2448+.RE
2449+.SS Extension: \f[C]styles\f[]
2450+.PP
2451+Read all docx styles as divs (for paragraph styles) and spans (for
2452+character styles) regardless of whether pandoc understands the meaning
2453+of these styles.
2454+This can be used with docx custom styles.
2455+Disabled by default.
2456+.TP
2457+.B input formats
2458+\f[C]docx\f[]
23422459.RS
23432460.RE
23442461.SS Extension: \f[C]amuse\f[]
@@ -2741,7 +2858,7 @@ Here \f[C]mycode\f[] is an identifier, \f[C]haskell\f[] and
27412858with value \f[C]100\f[].
27422859Some output formats can use this information to do syntax highlighting.
27432860Currently, the only output formats that uses this information are HTML,
2744−LaTeX, Docx, and Ms.
2861+LaTeX, Docx, Ms, and PowerPoint.
27452862If highlighting is supported for your output format and language, then
27462863the code block above will appear highlighted, with numbered lines.
27472864(To see which languages are supported, type
@@ -3720,7 +3837,8 @@ For example:
37203837.nf
37213838\f[C]
37223839header\-includes:
3723−\-\ ```{=latex}
3840+\-\ |
3841+\ \ ```{=latex}
37243842\ \ \\let\\oldsection\\section
37253843\ \ \\renewcommand{\\section}[1]{\\clearpage\\oldsection{#1}}
37263844\ \ ```
@@ -4142,9 +4260,29 @@ This\ is\ `<a>html</a>`{=html}
41424260\f[]
41434261.fi
41444262.PP
4263+This can be useful to insert raw xml into \f[C]docx\f[] documents, e.g.
4264+a pagebreak:
4265+.IP
4266+.nf
4267+\f[C]
4268+```{=openxml}
4269+<w:p>
4270+\ \ <w:r>
4271+\ \ \ \ <w:br\ w:type="page"/>
4272+\ \ </w:r>
4273+</w:p>
4274+```
4275+\f[]
4276+.fi
4277+.PP
41454278The format name should match the target format name (see
41464279\f[C]\-t/\-\-to\f[], above, for a list, or use
41474280\f[C]pandoc\ \-\-list\-output\-formats\f[]).
4281+Use \f[C]openxml\f[] for \f[C]docx\f[] output, \f[C]opendocument\f[] for
4282+\f[C]odt\f[] output, \f[C]html5\f[] for \f[C]epub3\f[] output,
4283+\f[C]html4\f[] for \f[C]epub2\f[] output, and \f[C]latex\f[],
4284+\f[C]beamer\f[], \f[C]ms\f[], or \f[C]html5\f[] for \f[C]pdf\f[] output
4285+(depending on what you use for \f[C]\-\-pdf\-engine\f[]).
41484286.PP
41494287This extension presupposes that the relevant kind of inline code or
41504288fenced code block is enabled.
@@ -5204,9 +5342,42 @@ reveal.js.
52045342By default, these writers produce lists that display "all at once." If
52055343you want your lists to display incrementally (one item at a time), use
52065344the \f[C]\-i\f[] option.
5207−If you want a particular list to depart from the default (that is, to
5345+If you want a particular list to depart from the default, put it in a
5346+\f[C]div\f[] block with class \f[C]incremental\f[] or
5347+\f[C]nonincremental\f[].
5348+So, for example, using the \f[C]fenced\ div\f[] syntax, the following
5349+would be incremental regardless of the document default:
5350+.IP
5351+.nf
5352+\f[C]
5353+:::\ incremental
5354+
5355+\-\ Eat\ spaghetti
5356+\-\ Drink\ wine
5357+
5358+:::
5359+\f[]
5360+.fi
5361+.PP
5362+or
5363+.IP
5364+.nf
5365+\f[C]
5366+:::\ nonincremental
5367+
5368+\-\ Eat\ spaghetti
5369+\-\ Drink\ wine
5370+
5371+:::
5372+\f[]
5373+.fi
5374+.PP
5375+While using \f[C]incremental\f[] and \f[C]nonincremental\f[] divs are
5376+the recommended method of setting incremental lists on a per\-case
5377+basis, an older method is also supported: putting lists inside a
5378+blockquote will depart from the document default (that is, it will
52085379display incrementally without the \f[C]\-i\f[] option and all at once
5209−with the \f[C]\-i\f[] option), put it in a block quote:
5380+with the \f[C]\-i\f[] option):
52105381.IP
52115382.nf
52125383\f[C]
@@ -5215,7 +5386,7 @@ with the \f[C]\-i\f[] option), put it in a block quote:
52155386\f[]
52165387.fi
52175388.PP
5218−In this way incremental and nonincremental lists can be mixed in a
5389+Both methods allow incremental and nonincremental lists to be mixed in a
52195390single document.
52205391.SS Inserting pauses
52215392.PP
@@ -5286,7 +5457,7 @@ This is recommended especially for bibliographies:
52865457.fi
52875458.SS Speaker notes
52885459.PP
5289−reveal.js has good support for speaker notes.
5460+Speaker notes are supported in reveal.js and PowerPoint (pptx) output.
52905461You can add notes to your Markdown document thus:
52915462.IP
52925463.nf
@@ -5302,8 +5473,11 @@ This\ is\ my\ note.
53025473\f[]
53035474.fi
53045475.PP
5305−To show the notes window, press \f[C]s\f[] while viewing the
5306−presentation.
5476+To show the notes window in reveal.js, press \f[C]s\f[] while viewing
5477+the presentation.
5478+Speaker notes in PowerPoint will be available, as usual, in handouts and
5479+presenter view.
5480+.PP
53075481Notes are not yet supported for other slide formats, but the notes will
53085482not appear on the slides themselves.
53095483.SS Columns
@@ -5342,6 +5516,49 @@ All of the other frame attributes described in Section 8.1 of the Beamer
53425516User\[aq]s Guide may also be used: \f[C]allowdisplaybreaks\f[],
53435517\f[C]allowframebreaks\f[], \f[C]b\f[], \f[C]c\f[], \f[C]t\f[],
53445518\f[C]environment\f[], \f[C]label\f[], \f[C]plain\f[], \f[C]shrink\f[].
5519+.SS Background in reveal.js
5520+.PP
5521+Background images can be added to self\-contained reveal.js slideshows.
5522+.PP
5523+For the same image on every slide, use the reveal.js configuration
5524+option \f[C]parallaxBackgroundImage\f[] either in the YAML metadata
5525+block or as a command\-line variable.
5526+You can also set \f[C]parallaxBackgroundHorizontal\f[] and
5527+\f[C]parallaxBackgroundVertical\f[] the same way and must also set
5528+\f[C]parallaxBackgroundSize\f[] to have your values take effect.
5529+.PP
5530+To set an image for a particular slide, add
5531+\f[C]{data\-background\-image="/path/to/image"}\f[] to the first
5532+slide\-level header on the slide (which may even be empty).
5533+.PP
5534+In reveal.js\[aq]s overview mode, the parallaxBackgroundImage will show
5535+up only on the first slide.
5536+.PP
5537+Other background settings also work on individual slides, including
5538+\f[C]data\-background\-size\f[], \f[C]data\-background\-repeat\f[],
5539+\f[C]data\-background\-color\f[], \f[C]data\-transition\f[], and
5540+\f[C]data\-transition\-speed\f[].
5541+.PP
5542+See the reveal.js documentation for more details.
5543+.PP
5544+For example:
5545+.IP
5546+.nf
5547+\f[C]
5548+\-\-\-
5549+title:\ My\ Slideshow
5550+parallaxBackgroundImage:\ /path/to/my/background_image.png
5551+\-\-\-
5552+
5553+##\ Slide\ One
5554+
5555+Slide\ 1\ has\ background_image.png\ as\ its\ background.
5556+
5557+##\ {data\-background\-image="/path/to/special_image.jpg"}
5558+
5559+Slide\ 2\ has\ a\ special\ image\ for\ its\ background,\ even\ though\ the\ header\ has\ no\ content.
5560+\f[]
5561+.fi
53455562.SH CREATING EPUBS WITH PANDOC
53465563.SS EPUB Metadata
53475564.PP
@@ -5532,7 +5749,62 @@ To see a list of highlight styles, type
55325749\f[C]pandoc\ \-\-list\-highlight\-styles\f[].
55335750.PP
55345751To disable highlighting, use the \f[C]\-\-no\-highlight\f[] option.
5535−.SH CUSTOM STYLES IN DOCX OUTPUT
5752+.SH CUSTOM STYLES IN DOCX
5753+.SS Input
5754+.PP
5755+The docx reader, by default, only reads those styles that it can convert
5756+into pandoc elements, either by direct conversion or interpreting the
5757+derivation of the input document\[aq]s styles.
5758+.PP
5759+By enabling the \f[C]styles\f[] extension in the docx reader
5760+(\f[C]\-f\ docx+styles\f[]), you can produce output that maintains the
5761+styles of the input document, using the \f[C]custom\-style\f[] class.
5762+Paragraph styles are interpreted as divs, while character styles are
5763+interpreted as spans.
5764+.PP
5765+For example, using the \f[C]custom\-style\-reference.docx\f[] file in
5766+the test directory, we have the following different outputs:
5767+.PP
5768+Without the \f[C]+styles\f[] extension:
5769+.IP
5770+.nf
5771+\f[C]
5772+$\ pandoc\ test/docx/custom\-style\-reference.docx\ \-f\ docx\ \-t\ markdown
5773+This\ is\ some\ text.
5774+
5775+This\ is\ text\ with\ an\ *emphasized*\ text\ style.\ And\ this\ is\ text\ with\ a
5776+**strengthened**\ text\ style.
5777+
5778+>\ Here\ is\ a\ styled\ paragraph\ that\ inherits\ from\ Block\ Text.
5779+\f[]
5780+.fi
5781+.PP
5782+And with the extension:
5783+.IP
5784+.nf
5785+\f[C]
5786+$\ pandoc\ test/docx/custom\-style\-reference.docx\ \-f\ docx+styles\ \-t\ markdown
5787+
5788+:::\ {custom\-style="FirstParagraph"}
5789+This\ is\ some\ text.
5790+:::
5791+
5792+:::\ {custom\-style="BodyText"}
5793+This\ is\ text\ with\ an\ [emphasized]{custom\-style="Emphatic"}\ text\ style.
5794+And\ this\ is\ text\ with\ a\ [strengthened]{custom\-style="Strengthened"}
5795+text\ style.
5796+:::
5797+
5798+:::\ {custom\-style="MyBlockStyle"}
5799+>\ Here\ is\ a\ styled\ paragraph\ that\ inherits\ from\ Block\ Text.
5800+:::
5801+\f[]
5802+.fi
5803+.PP
5804+With these custom styles, you can use your input document as a
5805+reference\-doc while creating docx output (see below), and maintain the
5806+same styles in your input and output files.
5807+.SS Output
55365808.PP
55375809By default, pandoc\[aq]s docx output applies a predefined set of styles
55385810for blocks such as paragraphs and block quotes, and uses largely default
pandoc.cabal+86−73
@@ -1,17 +1,17 @@
11name: pandoc
2−version: 2.1.1
2+version: 2.2
33cabal-version: >= 1.10
44build-type: Custom
5−license: GPL
5+license: GPL-2
66license-file: COPYING.md
77copyright: (c) 2006-2018 John MacFarlane
88author: John MacFarlane <jgm@berkeley.edu>
99maintainer: John MacFarlane <jgm@berkeley.edu>
1010bug-reports: https://github.com/jgm/pandoc/issues
1111stability: alpha
12−homepage: http://pandoc.org
12+homepage: https://pandoc.org
1313category: Text
14−tested-with: GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2
14+tested-with: GHC == 7.10.3, GHC == 8.0.2, GHC == 8.2.2, GHC == 8.4.1
1515synopsis: Conversion between markup formats
1616description: Pandoc is a Haskell library for converting from one markup
1717 format to another, and a command-line tool that uses
@@ -19,11 +19,11 @@ description: Pandoc is a Haskell library for converting from one markup
1919 (subsets of) HTML, reStructuredText, LaTeX, DocBook, JATS,
2020 MediaWiki markup, TWiki markup, TikiWiki markup, Creole 1.0,
2121 Haddock markup, OPML, Emacs Org-Mode, Emacs Muse, txt2tags,
22− Vimwiki, Word Docx, ODT, and Textile, and it can write
23− Markdown, reStructuredText, XHTML, HTML 5, LaTeX, ConTeXt,
24− DocBook, JATS, OPML, TEI, OpenDocument, ODT, Word docx,
25− RTF, MediaWiki, DokuWiki, ZimWiki, Textile, groff man,
26− groff ms, plain text, Emacs Org-Mode, AsciiDoc,
22+ Vimwiki, Word Docx, ODT, EPUB, FictionBook2, and Textile,
23+ and it can write Markdown, reStructuredText, XHTML, HTML 5,
24+ LaTeX, ConTeXt, DocBook, JATS, OPML, TEI, OpenDocument,
25+ ODT, Word docx, RTF, MediaWiki, DokuWiki, ZimWiki, Textile,
26+ groff man, groff ms, plain text, Emacs Org-Mode, AsciiDoc,
2727 Haddock markup, EPUB (v2 and v3), FictionBook2, InDesign
2828 ICML, Muse, LaTeX beamer slides, PowerPoint, and several
2929 kinds of HTML/JavaScript slide shows (S5, Slidy, Slideous,
@@ -102,7 +102,6 @@ data-files:
102102 data/odt/META-INF/manifest.xml
103103 -- source files for reference.pptx
104104 data/pptx/_rels/.rels
105− data/pptx/docProps/thumbnail.jpeg
106105 data/pptx/docProps/app.xml
107106 data/pptx/docProps/core.xml
108107 data/pptx/ppt/slideLayouts/_rels/slideLayout1.xml.rels
@@ -149,8 +148,6 @@ data-files:
149148 data/pptx/[Content_Types].xml
150149 -- stylesheet for EPUB writer
151150 data/epub.css
152− -- data for LaTeXMathML writer
153− data/LaTeXMathML.js
154151 -- data for dzslides writer
155152 data/dzslides/template.html
156153 -- default abbreviations file
@@ -304,6 +301,8 @@ extra-source-files:
304301 test/fb2/images-embedded.html
305302 test/fb2/images-embedded.fb2
306303 test/fb2/test-small.png
304+ test/fb2/reader/*.fb2
305+ test/fb2/reader/*.native
307306 test/fb2/test.jpg
308307 test/docx/*.docx
309308 test/docx/golden/*.docx
@@ -335,18 +334,10 @@ flag trypandoc
335334 Description: Build trypandoc cgi executable.
336335 Default: False
337336
338−flag weigh-pandoc
339− Description: Build weigh-pandoc to measure memory usage.
340− Default: False
341−
342337flag network-uri
343338 Description: Get Network.URI from the network-uri package
344339 Default: True
345340
346−flag old-locale
347− Description: Use old-locale and time < 1.5
348− Default: False
349−
350341custom-setup
351342 setup-depends: base, Cabal
352343
@@ -357,12 +348,13 @@ library
357348 unordered-containers >= 0.2 && < 0.3,
358349 parsec >= 3.1 && < 3.2,
359350 mtl >= 2.2 && < 2.3,
360− exceptions >= 0.8 && < 0.9,
351+ exceptions >= 0.8 && < 0.11,
361352 filepath >= 1.1 && < 1.5,
362353 process >= 1.2.3 && < 1.7,
363354 directory >= 1 && < 1.4,
364355 bytestring >= 0.9 && < 0.11,
365356 text >= 0.11 && < 1.3,
357+ time >= 1.5 && < 1.10,
366358 safe >= 0.3 && < 0.4,
367359 zip-archive >= 0.2.3.4 && < 0.4,
368360 HTTP >= 4000.0.5 && < 4000.4,
@@ -370,25 +362,25 @@ library
370362 xml >= 1.3.12 && < 1.4,
371363 split >= 0.2 && < 0.3,
372364 random >= 1 && < 1.2,
373− pandoc-types >= 1.17.3 && < 1.18,
374− aeson >= 0.7 && < 1.3,
365+ pandoc-types >= 1.17.4.2 && < 1.18,
366+ aeson >= 0.7 && < 1.4,
375367 aeson-pretty >= 0.8.5 && < 0.9,
376− tagsoup >= 0.14.3 && < 0.15,
368+ tagsoup >= 0.14.6 && < 0.15,
377369 base64-bytestring >= 0.1 && < 1.1,
378370 zlib >= 0.5 && < 0.7,
379− skylighting >= 0.5.1 && < 0.7,
371+ skylighting >= 0.5.1 && < 0.8,
380372 data-default >= 0.4 && < 0.8,
381− temporary >= 1.1 && < 1.3,
373+ temporary >= 1.1 && < 1.4,
382374 blaze-html >= 0.9 && < 0.10,
383375 blaze-markup >= 0.8 && < 0.9,
384376 yaml >= 0.8.8.2 && < 0.9,
385377 scientific >= 0.2 && < 0.4,
386378 vector >= 0.10 && < 0.13,
387− hslua >= 0.9.5 && < 0.10,
379+ hslua >= 0.9.5 && < 0.9.6,
388380 hslua-module-text >= 0.1.2 && < 0.2,
389381 binary >= 0.5 && < 0.10,
390382 SHA >= 1.6 && < 1.7,
391− haddock-library >= 1.1 && < 1.5,
383+ haddock-library >= 1.1 && < 1.6,
392384 deepseq >= 1.3 && < 1.5,
393385 JuicyPixels >= 3.1.6.1 && < 3.3,
394386 Glob >= 0.7 && < 0.10,
@@ -396,17 +388,18 @@ library
396388 doctemplates >= 0.2.1 && < 0.3,
397389 http-client >= 0.4.30 && < 0.6,
398390 http-client-tls >= 0.2.4 && < 0.4,
399− http-types >= 0.8 && < 0.12,
391+ http-types >= 0.8 && < 0.13,
400392 case-insensitive >= 1.2 && < 1.3
393+ if impl(ghc < 8.0)
394+ build-depends: semigroups == 0.18.*
395+ if impl(ghc < 8.4)
396+ hs-source-dirs: prelude
397+ other-modules: Prelude
398+ build-depends: base-compat >= 0.9
401399 if os(windows)
402400 cpp-options: -D_WINDOWS
403401 else
404402 build-depends: unix >= 2.4 && < 2.8
405− if flag(old-locale)
406− build-depends: old-locale >= 1 && < 1.1,
407− time >= 1.2 && < 1.5
408− else
409− build-depends: time >= 1.5 && < 1.9
410403 if flag(network-uri)
411404 build-depends: network-uri >= 2.6 && < 2.7, network >= 2.6
412405 else
@@ -418,12 +411,8 @@ library
418411 if os(windows)
419412 cpp-options: -D_WINDOWS
420413 ghc-options: -Wall -fno-warn-unused-do-bind
421− ghc-prof-options: -fprof-auto-exported
422− default-language: Haskell98
423− other-extensions: PatternGuards, OverloadedStrings,
424− ScopedTypeVariables, GeneralizedNewtypeDeriving,
425− RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
426− FlexibleInstances
414+ default-language: Haskell2010
415+ other-extensions: NoImplicitPrelude
427416 hs-source-dirs: src
428417
429418 exposed-modules: Text.Pandoc,
@@ -459,6 +448,7 @@ library
459448 Text.Pandoc.Readers.EPUB,
460449 Text.Pandoc.Readers.Muse,
461450 Text.Pandoc.Readers.Man,
451+ Text.Pandoc.Readers.FB2,
462452 Text.Pandoc.Writers,
463453 Text.Pandoc.Writers.Native,
464454 Text.Pandoc.Writers.Docbook,
@@ -555,22 +545,23 @@ library
555545 Text.Pandoc.UUID,
556546 Text.Pandoc.Translations,
557547 Text.Pandoc.Slides,
558− Text.Pandoc.Compat.Time,
559548 Paths_pandoc
560549
561550 buildable: True
562551
563552executable pandoc
564553 build-depends: pandoc, base >= 4.7 && < 5
554+ if impl(ghc < 8.0)
555+ build-depends: semigroups == 0.18.*
556+ if impl(ghc < 8.4)
557+ hs-source-dirs: prelude
558+ other-modules: Prelude
559+ build-depends: base-compat >= 0.9
565560 ghc-options: -rtsopts -with-rtsopts=-K16m -Wall -fno-warn-unused-do-bind -threaded
566− ghc-prof-options: -fprof-auto-exported -rtsopts -with-rtsopts=-K16m
567561 if flag(static)
568562 ld-options: -static
569− default-language: Haskell98
570− other-extensions: PatternGuards, OverloadedStrings,
571− ScopedTypeVariables, GeneralizedNewtypeDeriving,
572− RelaxedPolyRec, DeriveDataTypeable, TypeSynonymInstances,
573− FlexibleInstances
563+ default-language: Haskell2010
564+ other-extensions: NoImplicitPrelude
574565 hs-source-dirs: .
575566 main-is: pandoc.hs
576567 buildable: True
@@ -580,27 +571,38 @@ executable trypandoc
580571 main-is: trypandoc.hs
581572 hs-source-dirs: trypandoc
582573 default-language: Haskell2010
574+ other-extensions: NoImplicitPrelude
583575 if flag(trypandoc)
584576 build-depends: base, aeson, pandoc,
585577 text, wai-extra, wai >= 0.3, http-types
586578 buildable: True
587579 else
588580 buildable: False
581+ if impl(ghc < 8.0)
582+ build-depends: semigroups == 0.18.*
583+ if impl(ghc < 8.4)
584+ hs-source-dirs: prelude
585+ other-modules: Prelude
586+ build-depends: base-compat >= 0.9
589587
590−executable weigh-pandoc
588+benchmark weigh-pandoc
589+ type: exitcode-stdio-1.0
591590 main-is: weigh-pandoc.hs
592591 hs-source-dirs: benchmark
593− if flag(weigh-pandoc)
594− build-depends: pandoc,
595− base >= 4.2 && < 5,
596− text,
597− weigh >= 0.0 && < 0.1,
598− mtl >= 2.2 && < 2.3
599− buildable: True
600− else
601− buildable: False
602− ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind
603− default-language: Haskell98
592+ build-depends: pandoc,
593+ base >= 4.2 && < 5,
594+ text,
595+ weigh >= 0.0 && < 0.1,
596+ mtl >= 2.2 && < 2.3
597+ if impl(ghc < 8.0)
598+ build-depends: semigroups == 0.18.*
599+ if impl(ghc < 8.4)
600+ hs-source-dirs: prelude
601+ other-modules: Prelude
602+ build-depends: base-compat >= 0.9
603+ ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
604+ default-language: Haskell2010
605+ other-extensions: NoImplicitPrelude
604606
605607test-suite test-pandoc
606608 type: exitcode-stdio-1.0
@@ -608,20 +610,20 @@ test-suite test-pandoc
608610 hs-source-dirs: test
609611 build-depends: base >= 4.2 && < 5,
610612 pandoc,
611− pandoc-types >= 1.17.3 && < 1.18,
613+ pandoc-types >= 1.17.4.2 && < 1.18,
612614 bytestring >= 0.9 && < 0.11,
613615 base64-bytestring >= 0.1 && < 1.1,
614616 text >= 0.11 && < 1.3,
615− time >= 1.5 && < 1.9,
617+ time >= 1.5 && < 1.10,
616618 directory >= 1 && < 1.4,
617619 filepath >= 1.1 && < 1.5,
618− hslua >= 0.9 && < 0.10,
620+ hslua >= 0.9.5 && < 0.9.6,
619621 process >= 1.2.3 && < 1.7,
620− temporary >= 1.1 && < 1.3,
622+ temporary >= 1.1 && < 1.4,
621623 Diff >= 0.2 && < 0.4,
622624 tasty >= 0.11 && < 1.1,
623625 tasty-hunit >= 0.9 && < 0.11,
624− tasty-quickcheck >= 0.8 && < 0.10,
626+ tasty-quickcheck >= 0.8 && < 0.11,
625627 tasty-golden >= 2.3 && < 2.4,
626628 QuickCheck >= 2.4 && < 2.12,
627629 containers >= 0.4.2.1 && < 0.6,
@@ -629,11 +631,12 @@ test-suite test-pandoc
629631 zip-archive >= 0.2.3.4 && < 0.4,
630632 xml >= 1.3.12 && < 1.4,
631633 Glob >= 0.7 && < 0.10
632− if flag(old-locale)
633− build-depends: old-locale >= 1 && < 1.1,
634− time >= 1.2 && < 1.5
635− else
636− build-depends: time >= 1.5 && < 1.9
634+ if impl(ghc < 8.0)
635+ build-depends: semigroups == 0.18.*
636+ if impl(ghc < 8.4)
637+ hs-source-dirs: prelude
638+ other-modules: Prelude
639+ build-depends: base-compat >= 0.9
637640 other-modules: Tests.Old
638641 Tests.Command
639642 Tests.Helpers
@@ -652,6 +655,7 @@ test-suite test-pandoc
652655 Tests.Readers.Org.Block.Table
653656 Tests.Readers.Org.Directive
654657 Tests.Readers.Org.Inline
658+ Tests.Readers.Org.Inline.Citation
655659 Tests.Readers.Org.Inline.Note
656660 Tests.Readers.Org.Inline.Smart
657661 Tests.Readers.Org.Meta
@@ -664,6 +668,7 @@ test-suite test-pandoc
664668 Tests.Readers.Muse
665669 Tests.Readers.Creole
666670 Tests.Readers.Man
671+ Tests.Readers.FB2
667672 Tests.Writers.Native
668673 Tests.Writers.ConTeXt
669674 Tests.Writers.Docbook
@@ -682,7 +687,8 @@ test-suite test-pandoc
682687 Tests.Writers.Powerpoint
683688 Tests.Writers.OOXML
684689 ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
685− default-language: Haskell98
690+ default-language: Haskell2010
691+ other-extensions: NoImplicitPrelude
686692
687693benchmark benchmark-pandoc
688694 type: exitcode-stdio-1.0
@@ -692,6 +698,13 @@ benchmark benchmark-pandoc
692698 time, bytestring, containers,
693699 base >= 4.2 && < 5,
694700 text >= 0.11 && < 1.3,
695− criterion >= 1.0 && < 1.4
696− ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind
697− default-language: Haskell98
701+ criterion >= 1.0 && < 1.5
702+ if impl(ghc < 8.0)
703+ build-depends: semigroups == 0.18.*
704+ if impl(ghc < 8.4)
705+ hs-source-dirs: prelude
706+ other-modules: Prelude
707+ build-depends: base-compat >= 0.9
708+ ghc-options: -rtsopts -Wall -fno-warn-unused-do-bind -threaded
709+ default-language: Haskell2010
710+ other-extensions: NoImplicitPrelude
pandoc.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ Parses command-line options and calls the appropriate readers and
2930writers.
3031-}
3132module Main where
33+import Prelude
3234import qualified Control.Exception as E
3335import Text.Pandoc.App (convertWithOpts, defaultOpts, options, parseOptions)
3436import Text.Pandoc.Error (handleError)
prelude/Prelude.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE PackageImports #-}
3+{-# LANGUAGE CPP #-}
4+
5+-- The intent is that this Prelude provide the API of
6+-- the base 4.11 Prelude in a way that is portable for
7+-- all base versions.
8+
9+module Prelude
10+(
11+ module Prelude.Compat
12+, Semigroup(..)
13+)
14+where
15+
16+import Prelude.Compat
17+import Data.Semigroup (Semigroup(..)) -- includes (<>)
src/Text/Pandoc/App.hs+45−58
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -42,6 +43,7 @@ module Text.Pandoc.App (
4243 , options
4344 , applyFilters
4445 ) where
46+import Prelude
4547import qualified Control.Exception as E
4648import Control.Monad
4749import Control.Monad.Except (catchError, throwError)
@@ -50,11 +52,10 @@ import Data.Aeson (defaultOptions)
5052import Data.Aeson.TH (deriveJSON)
5153import qualified Data.ByteString as BS
5254import qualified Data.ByteString.Lazy as B
53−import Data.Char (toLower, toUpper)
55+import Data.Char (toLower, toUpper, isAscii, ord)
5456import Data.List (find, intercalate, isPrefixOf, isSuffixOf, sort)
5557import qualified Data.Map as M
5658import Data.Maybe (fromMaybe, isJust, isNothing)
57−import Data.Monoid
5859import qualified Data.Set as Set
5960import Data.Text (Text)
6061import qualified Data.Text as T
@@ -65,7 +66,12 @@ import Data.Yaml (decode)
6566import qualified Data.Yaml as Yaml
6667import GHC.Generics
6768import Network.URI (URI (..), parseURI)
69+#ifdef EMBED_DATA_FILES
70+import Text.Pandoc.Data (dataFiles)
71+#else
72+import System.Directory (getDirectoryContents)
6873import Paths_pandoc (getDataDir)
74+#endif
6975import Data.Aeson.Encode.Pretty (encodePretty', Config(..), keyOrder,
7076 defConfig, Indent(..), NumberFormat(..))
7177import Skylighting (Style, Syntax (..), defaultSyntaxMap, parseTheme,
@@ -87,7 +93,7 @@ import Text.Pandoc.Highlighting (highlightingStyles)
8793import Text.Pandoc.PDF (makePDF)
8894import Text.Pandoc.SelfContained (makeDataURI, makeSelfContained)
8995import Text.Pandoc.Shared (eastAsianLineBreakFilter, stripEmptyParagraphs,
90− headerShift, isURI, ordNub, safeRead, tabFilter)
96+ headerShift, isURI, ordNub, safeRead, tabFilter, uriPathToPath)
9197import qualified Text.Pandoc.UTF8 as UTF8
9298import Text.Pandoc.Writers.Math (defaultKaTeXURL, defaultMathJaxURL)
9399import Text.Pandoc.XML (toEntities)
@@ -217,17 +223,16 @@ convertWithOpts opts = do
217223 then pdfWriterAndProg (optWriter opts) (optPdfEngine opts)
218224 else return (nonPdfWriterName $ optWriter opts, Nothing)
219225
220− let format = baseWriterName
226+ let format = map toLower $ baseWriterName
221227 $ takeFileName writerName -- in case path to lua script
222228
223229 -- disabling the custom writer for now
224230 (writer, writerExts) <-
225231 if ".lua" `isSuffixOf` format
226− -- note: use non-lowercased version writerName
227232 then return (TextWriter
228233 (\o d -> writeCustom writerName o d)
229234 :: Writer PandocIO, mempty)
230− else case getWriter writerName of
235+ else case getWriter (map toLower writerName) of
231236 Left e -> E.throwIO $ PandocAppError $
232237 if format == "pdf"
233238 then e ++
@@ -351,12 +356,6 @@ convertWithOpts opts = do
351356 maybe return (addStringAsVariable "epub-cover-image")
352357 (optEpubCoverImage opts)
353358 >>=
354− (\vars -> case optHTMLMathMethod opts of
355− LaTeXMathML Nothing -> do
356− s <- UTF8.toString <$> readDataFile "LaTeXMathML.js"
357− return $ ("mathml-script", s) : vars
358− _ -> return vars)
359− >>=
360359 (\vars -> if format == "dzslides"
361360 then do
362361 dztempl <- UTF8.toString <$> readDataFile
@@ -513,16 +512,19 @@ convertWithOpts opts = do
513512 let htmlFormat = format `elem`
514513 ["html","html4","html5","s5","slidy",
515514 "slideous","dzslides","revealjs"]
516− handleEntities = if (htmlFormat ||
517− format == "docbook4" ||
518− format == "docbook5" ||
519− format == "docbook") && optAscii opts
520− then toEntities
521− else id
515+ escape
516+ | optAscii opts
517+ , htmlFormat || format == "docbook4" ||
518+ format == "docbook5" || format == "docbook" ||
519+ format == "jats" || format == "opml" ||
520+ format == "icml" = toEntities
521+ | optAscii opts
522+ , format == "ms" || format == "man" = groffEscape
523+ | otherwise = id
522524 addNl = if standalone
523525 then id
524526 else (<> T.singleton '\n')
525− output <- (addNl . handleEntities) <$> f writerOptions doc
527+ output <- (addNl . escape) <$> f writerOptions doc
526528 writerFn eol outputFile =<<
527529 if optSelfContained opts && htmlFormat
528530 -- TODO not maximally efficient; change type
@@ -530,6 +532,12 @@ convertWithOpts opts = do
530532 then T.pack <$> makeSelfContained (T.unpack output)
531533 else return output
532534
535+groffEscape :: Text -> Text
536+groffEscape = T.concatMap toUchar
537+ where toUchar c
538+ | isAscii c = T.singleton c
539+ | otherwise = T.pack $ printf "\\[u%04X]" (ord c)
540+
533541type Transform = Pandoc -> Pandoc
534542
535543isTextFormat :: String -> Bool
@@ -729,6 +737,7 @@ defaultReaderName fallback (x:xs) =
729737 ".odt" -> "odt"
730738 ".pdf" -> "pdf" -- so we get an "unknown reader" error
731739 ".doc" -> "doc" -- so we get an "unknown reader" error
740+ ".fb2" -> "fb2"
732741 _ -> defaultReaderName fallback xs
733742
734743-- Determine default writer based on output file extension
@@ -786,7 +795,7 @@ readSource src = case parseURI src of
786795 readURI src
787796 | uriScheme u == "file:" ->
788797 liftIO $ UTF8.toText <$>
789− BS.readFile (uriPath u)
798+ BS.readFile (uriPathToPath $ uriPath u)
790799 _ -> liftIO $ UTF8.toText <$>
791800 BS.readFile src
792801
@@ -834,8 +843,7 @@ options =
834843
835844 , Option "tw" ["to","write"]
836845 (ReqArg
837− (\arg opt -> return opt { optWriter =
838− Just (map toLower arg) })
846+ (\arg opt -> return opt { optWriter = Just arg })
839847 "FORMAT")
840848 ""
841849
@@ -967,6 +975,9 @@ options =
967975 setUserDataDir Nothing
968976 getDefaultTemplate arg
969977 case templ of
978+ Right "" -> do -- e.g. for docx, odt, json:
979+ E.throwIO $ PandocCouldNotFindDataFileError
980+ ("templates/default." ++ arg)
970981 Right t -> UTF8.hPutStr stdout t
971982 Left e -> E.throwIO e
972983 exitSuccess)
@@ -1392,40 +1403,6 @@ options =
13921403 "URL")
13931404 "" -- Use KaTeX for HTML Math
13941405
1395− , Option "m" ["latexmathml", "asciimathml"]
1396− (OptArg
1397− (\arg opt -> do
1398− deprecatedOption "--latexmathml, --asciimathml, -m" ""
1399− return opt { optHTMLMathMethod = LaTeXMathML arg })
1400− "URL")
1401− "" -- "Use LaTeXMathML script in html output"
1402−
1403− , Option "" ["mimetex"]
1404− (OptArg
1405− (\arg opt -> do
1406− deprecatedOption "--mimetex" ""
1407− let url' = case arg of
1408− Just u -> u ++ "?"
1409− Nothing -> "/cgi-bin/mimetex.cgi?"
1410− return opt { optHTMLMathMethod = WebTeX url' })
1411− "URL")
1412− "" -- "Use mimetex for HTML math"
1413−
1414− , Option "" ["jsmath"]
1415− (OptArg
1416− (\arg opt -> do
1417− deprecatedOption "--jsmath" ""
1418− return opt { optHTMLMathMethod = JsMath arg})
1419− "URL")
1420− "" -- "Use jsMath for HTML math"
1421−
1422− , Option "" ["gladtex"]
1423− (NoArg
1424− (\opt -> do
1425− deprecatedOption "--gladtex" ""
1426− return opt { optHTMLMathMethod = GladTeX }))
1427− "" -- "Use gladtex for HTML math"
1428−
14291406 , Option "" ["abbreviations"]
14301407 (ReqArg
14311408 (\arg opt -> return opt { optAbbreviations = Just arg })
@@ -1471,7 +1448,7 @@ options =
14711448 , Option "" ["bash-completion"]
14721449 (NoArg
14731450 (\_ -> do
1474− ddir <- getDataDir
1451+ datafiles <- getDataFileNames
14751452 tpl <- runIOorExplode $
14761453 UTF8.toString <$>
14771454 readDefaultDataFile "bash_completion.tpl"
@@ -1483,7 +1460,7 @@ options =
14831460 (unwords readersNames)
14841461 (unwords writersNames)
14851462 (unwords $ map fst highlightingStyles)
1486− ddir
1463+ (unwords datafiles)
14871464 exitSuccess ))
14881465 "" -- "Print bash completion script"
14891466
@@ -1557,6 +1534,16 @@ options =
15571534
15581535 ]
15591536
1537+getDataFileNames :: IO [FilePath]
1538+getDataFileNames = do
1539+#ifdef EMBED_DATA_FILES
1540+ let allDataFiles = map fst dataFiles
1541+#else
1542+ allDataFiles <- filter (\x -> x /= "." && x /= "..") <$>
1543+ (getDataDir >>= getDirectoryContents)
1544+#endif
1545+ return $ "reference.docx" : "reference.odt" : "reference.pptx" : allDataFiles
1546+
15601547-- Returns usage message
15611548usageMessage :: String -> [OptDescr (Opt -> IO Opt)] -> String
15621549usageMessage programName = usageInfo (programName ++ " [OPTIONS] [FILES]")
src/Text/Pandoc/Asciify.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -30,6 +31,7 @@ ascii equivalents (used in constructing HTML identifiers).
3031-}
3132module Text.Pandoc.Asciify (toAsciiChar)
3233where
34+import Prelude
3335import Data.Char (isAscii)
3436import qualified Data.Map as M
3537
src/Text/Pandoc/BCP47.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -34,6 +35,7 @@ module Text.Pandoc.BCP47 (
3435 , renderLang
3536 )
3637where
38+import Prelude
3739import Control.Monad (guard)
3840import Data.Char (isAlphaNum, isAscii, isLetter, isLower, isUpper, toLower,
3941 toUpper)
src/Text/Pandoc/CSS.hs+2
@@ -1,9 +1,11 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Text.Pandoc.CSS ( foldOrElse
23 , pickStyleAttrProps
34 , pickStylesToKVs
45 )
56where
67
8+import Prelude
79import Text.Pandoc.Shared (trim)
810import Text.Parsec
911import Text.Parsec.String
src/Text/Pandoc/CSV.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2017–2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -34,6 +35,7 @@ module Text.Pandoc.CSV (
3435 ParseError
3536) where
3637
38+import Prelude
3739import Control.Monad (void)
3840import Data.Text (Text)
3941import qualified Data.Text as T
src/Text/Pandoc/Class.hs+17−6
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE PatternGuards #-}
34{-# LANGUAGE DeriveFunctor #-}
@@ -96,6 +97,7 @@ module Text.Pandoc.Class ( PandocMonad(..)
9697 , Translations
9798 ) where
9899
100+import Prelude
99101import Prelude hiding (readFile)
100102import System.Random (StdGen, next, mkStdGen)
101103import qualified System.Random as IO (newStdGen)
@@ -106,10 +108,11 @@ import Data.List (stripPrefix)
106108import qualified Data.Unique as IO (newUnique)
107109import qualified Text.Pandoc.UTF8 as UTF8
108110import qualified System.Directory as Directory
109−import Text.Pandoc.Compat.Time (UTCTime)
111+import Data.Time (UTCTime)
110112import Text.Pandoc.Logging
113+import Text.Pandoc.Shared (uriPathToPath)
111114import Text.Parsec (ParsecT, getPosition, sourceLine, sourceName)
112−import qualified Text.Pandoc.Compat.Time as IO (getCurrentTime)
115+import qualified Data.Time as IO (getCurrentTime)
113116import Text.Pandoc.MIME (MimeType, getMimeType, extensionFromMimeType)
114117import Text.Pandoc.Definition
115118import Data.Digest.Pure.SHA (sha1, showDigest)
@@ -475,6 +478,14 @@ liftIOError f u = do
475478 Left e -> throwError $ PandocIOError u e
476479 Right r -> return r
477480
481+-- | Show potential IO errors to the user continuing execution anyway
482+logIOError :: IO () -> PandocIO ()
483+logIOError f = do
484+ res <- liftIO $ tryIOError f
485+ case res of
486+ Left e -> report $ IgnoredIOError (E.displayException e)
487+ Right _ -> pure ()
488+
478489instance PandocMonad PandocIO where
479490 lookupEnv = liftIO . IO.lookupEnv
480491 getCurrentTime = liftIO IO.getCurrentTime
@@ -588,7 +599,7 @@ downloadOrRead s = do
588599 -- We don't want to treat C:/ as a scheme:
589600 Just u' | length (uriScheme u') > 2 -> openURL (show u')
590601 Just u' | uriScheme u' == "file:" ->
591− readLocalFile $ dropWhile (=='/') (uriPath u')
602+ readLocalFile $ uriPathToPath (uriPath u')
592603 _ -> readLocalFile fp -- get from local file system
593604 where readLocalFile f = do
594605 resourcePath <- getResourcePath
@@ -853,14 +864,14 @@ writeMedia :: FilePath -> MediaBag -> FilePath -> PandocIO ()
853864writeMedia dir mediabag subpath = do
854865 -- we join and split to convert a/b/c to a\b\c on Windows;
855866 -- in zip containers all paths use /
856− let fullpath = dir </> normalise subpath
867+ let fullpath = dir </> unEscapeString (normalise subpath)
857868 let mbcontents = lookupMedia subpath mediabag
858869 case mbcontents of
859870 Nothing -> throwError $ PandocResourceNotFound subpath
860871 Just (_, bs) -> do
861872 report $ Extracting fullpath
862873 liftIOError (createDirectoryIfMissing True) (takeDirectory fullpath)
863− liftIOError (\p -> BL.writeFile p bs) fullpath
874+ logIOError $ BL.writeFile fullpath bs
864875
865876adjustImagePath :: FilePath -> [FilePath] -> Inline -> Inline
866877adjustImagePath dir paths (Image attr lab (src, tit))
@@ -923,7 +934,7 @@ data FileInfo = FileInfo { infoFileMTime :: UTCTime
923934 }
924935
925936newtype FileTree = FileTree {unFileTree :: M.Map FilePath FileInfo}
926− deriving (Monoid)
937+ deriving (Semigroup, Monoid)
927938
928939getFileInfo :: FilePath -> FileTree -> Maybe FileInfo
929940getFileInfo fp tree =
src/Text/Pandoc/Compat/Time.hsdeleted−30
@@ -1,30 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−
3−{-
4−This compatibility module is needed because, in time 1.5, the
5−`defaultTimeLocale` function was moved from System.Locale (in the
6−old-locale library) into Data.Time.
7−
8−We support both behaviors because time 1.4 is a boot library for GHC
9−7.8. time 1.5 is a boot library for GHC 7.10.
10−
11−When support is dropped for GHC 7.8, this module may be obsoleted.
12−-}
13−
14−#if MIN_VERSION_time(1,5,0)
15−module Text.Pandoc.Compat.Time (
16− module Data.Time
17−)
18−where
19−import Data.Time
20−
21−#else
22−module Text.Pandoc.Compat.Time (
23− module Data.Time,
24− defaultTimeLocale
25−)
26−where
27−import Data.Time
28−import System.Locale ( defaultTimeLocale )
29−
30−#endif
src/Text/Pandoc/Data.hs+2
@@ -1,7 +1,9 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE TemplateHaskell #-}
23
34module Text.Pandoc.Data (dataFiles) where
45
6+import Prelude
57import qualified Data.ByteString as B
68import Data.FileEmbed
79import System.FilePath (splitDirectories)
src/Text/Pandoc/Emoji.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015 John MacFarlane <jgm@berkeley.edu>
34
@@ -28,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2829Emoji symbol lookup from canonical string identifier.
2930-}
3031module Text.Pandoc.Emoji ( emojis ) where
32+import Prelude
3133import qualified Data.Map as M
3234
3335emojis :: M.Map String String
src/Text/Pandoc/Error.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE DeriveDataTypeable #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-
@@ -34,6 +35,7 @@ module Text.Pandoc.Error (
3435 PandocError(..),
3536 handleError) where
3637
38+import Prelude
3739import Control.Exception (Exception)
3840import Data.Typeable (Typeable)
3941import GHC.Generics (Generic)
src/Text/Pandoc/Extensions.hs+16−5
@@ -1,3 +1,9 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
3+{-# LANGUAGE DeriveDataTypeable #-}
4+{-# LANGUAGE DeriveGeneric #-}
5+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
6+{-# LANGUAGE TemplateHaskell #-}
17{-
28Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
39
@@ -15,10 +21,6 @@ You should have received a copy of the GNU General Public License
1521along with this program; if not, write to the Free Software
1622Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
1723-}
18−{-# LANGUAGE DeriveDataTypeable #-}
19−{-# LANGUAGE DeriveGeneric #-}
20−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
21−{-# LANGUAGE TemplateHaskell #-}
2224
2325{- |
2426 Module : Text.Pandoc.Extensions
@@ -47,6 +49,7 @@ module Text.Pandoc.Extensions ( Extension(..)
4749 , githubMarkdownExtensions
4850 , multimarkdownExtensions )
4951where
52+import Prelude
5053import Data.Aeson (FromJSON (..), ToJSON (..), defaultOptions)
5154import Data.Aeson.TH (deriveJSON)
5255import Data.Bits (clearBit, setBit, testBit, (.|.))
@@ -59,9 +62,11 @@ import Text.Parsec
5962newtype Extensions = Extensions Integer
6063 deriving (Show, Read, Eq, Ord, Data, Typeable, Generic, ToJSON, FromJSON)
6164
65+instance Semigroup Extensions where
66+ (Extensions a) <> (Extensions b) = Extensions (a .|. b)
6267instance Monoid Extensions where
6368 mempty = Extensions 0
64− mappend (Extensions a) (Extensions b) = Extensions (a .|. b)
69+ mappend = (<>)
6570
6671extensionsFromList :: [Extension] -> Extensions
6772extensionsFromList = foldr enableExtension emptyExtensions
@@ -317,6 +322,8 @@ getDefaultExtensions "muse" = extensionsFromList
317322 Ext_auto_identifiers]
318323getDefaultExtensions "plain" = plainExtensions
319324getDefaultExtensions "gfm" = githubMarkdownExtensions
325+getDefaultExtensions "commonmark" = extensionsFromList
326+ [Ext_raw_html]
320327getDefaultExtensions "org" = extensionsFromList
321328 [Ext_citations,
322329 Ext_auto_identifiers]
@@ -338,6 +345,10 @@ getDefaultExtensions "latex" = extensionsFromList
338345 [Ext_smart,
339346 Ext_latex_macros,
340347 Ext_auto_identifiers]
348+getDefaultExtensions "beamer" = extensionsFromList
349+ [Ext_smart,
350+ Ext_latex_macros,
351+ Ext_auto_identifiers]
341352getDefaultExtensions "context" = extensionsFromList
342353 [Ext_smart,
343354 Ext_auto_identifiers]
src/Text/Pandoc/Filter.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2017 John MacFarlane <jgm@berkeley.edu>
34
@@ -33,6 +34,7 @@ module Text.Pandoc.Filter
3334 , applyFilters
3435 ) where
3536
37+import Prelude
3638import Data.Aeson (defaultOptions)
3739import Data.Aeson.TH (deriveJSON)
3840import Data.Foldable (foldrM)
src/Text/Pandoc/Filter/JSON.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ Programmatically modifications of pandoc documents via JSON filters.
2930-}
3031module Text.Pandoc.Filter.JSON (apply) where
3132
33+import Prelude
3234import Control.Monad (unless, when)
3335import Control.Monad.Trans (MonadIO (liftIO))
3436import Data.Aeson (eitherDecode', encode)
src/Text/Pandoc/Filter/Lua.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ Apply Lua filters to modify a pandoc documents programmatically.
2930-}
3031module Text.Pandoc.Filter.Lua (apply) where
3132
33+import Prelude
3234import Control.Exception (throw)
3335import Text.Pandoc.Class (PandocIO)
3436import Text.Pandoc.Definition (Pandoc)
src/Text/Pandoc/Filter/Path.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -31,6 +32,7 @@ module Text.Pandoc.Filter.Path
3132 ( expandFilterPath
3233 ) where
3334
35+import Prelude
3436import Text.Pandoc.Class (PandocMonad, fileExists, getUserDataDir)
3537import System.FilePath ((</>), isRelative)
3638
src/Text/Pandoc/Highlighting.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -49,6 +50,7 @@ module Text.Pandoc.Highlighting ( highlightingStyles
4950 , fromListingsLanguage
5051 , toListingsLanguage
5152 ) where
53+import Prelude
5254import Control.Monad
5355import Data.Char (toLower)
5456import qualified Data.Map as M
src/Text/Pandoc/ImageSize.hs+7−5
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings, ScopedTypeVariables, CPP #-}
23{-# OPTIONS_GHC -fno-warn-type-defaults #-}
34{-
@@ -49,6 +50,7 @@ module Text.Pandoc.ImageSize ( ImageType(..)
4950 , showInPixel
5051 , showFl
5152 ) where
53+import Prelude
5254import Data.ByteString (ByteString, unpack)
5355import qualified Data.ByteString.Char8 as B
5456import qualified Data.ByteString.Lazy as BL
@@ -126,7 +128,7 @@ imageType img = case B.take 4 img of
126128 | B.take 4 (B.drop 1 $ B.dropWhile (/=' ') img) == "EPSF"
127129 -> return Eps
128130 "\x01\x00\x00\x00"
129− | B.take 4 (B.drop 40 img) == " EMF"
131+ | B.take 4 (B.drop 40 img) == " EMF"
130132 -> return Emf
131133 _ -> mzero
132134
@@ -361,9 +363,9 @@ svgSize opts img = do
361363 , dpiX = dpi
362364 , dpiY = dpi
363365 }
364−
366+
365367emfSize :: ByteString -> Maybe ImageSize
366−emfSize img =
368+emfSize img =
367369 let
368370 parseheader = runGetOrFail $ do
369371 skip 0x18 -- 0x00
@@ -388,11 +390,11 @@ emfSize img =
388390 , dpiX = fromIntegral dpiW
389391 , dpiY = fromIntegral dpiH
390392 }
391− in
393+ in
392394 case parseheader . BL.fromStrict $ img of
393395 Left _ -> Nothing
394396 Right (_, _, size) -> Just size
395−
397+
396398
397399jpegSize :: ByteString -> Either String ImageSize
398400jpegSize img =
src/Text/Pandoc/Logging.hs+15
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE DeriveDataTypeable #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE OverloadedStrings #-}
@@ -39,6 +40,7 @@ module Text.Pandoc.Logging (
3940 , messageVerbosity
4041 ) where
4142
43+import Prelude
4244import Control.Monad (mzero)
4345import Data.Aeson
4446import Data.Aeson.Encode.Pretty (Config (..), defConfig, encodePretty',
@@ -83,6 +85,7 @@ data LogMessage =
8385 | InlineNotRendered Inline
8486 | BlockNotRendered Block
8587 | DocxParserWarning String
88+ | IgnoredIOError String
8689 | CouldNotFetchResource String String
8790 | CouldNotDetermineImageSize String String
8891 | CouldNotConvertImage String String
@@ -99,6 +102,7 @@ data LogMessage =
99102 | Deprecated String String
100103 | NoTranslation String
101104 | CouldNotLoadTranslations String String
105+ | UnexpectedXmlElement String String
102106 deriving (Show, Eq, Data, Ord, Typeable, Generic)
103107
104108instance ToJSON LogMessage where
@@ -172,6 +176,8 @@ instance ToJSON LogMessage where
172176 ["contents" .= toJSON bl]
173177 DocxParserWarning s ->
174178 ["contents" .= Text.pack s]
179+ IgnoredIOError s ->
180+ ["contents" .= Text.pack s]
175181 CouldNotFetchResource fp s ->
176182 ["path" .= Text.pack fp,
177183 "message" .= Text.pack s]
@@ -209,6 +215,9 @@ instance ToJSON LogMessage where
209215 CouldNotLoadTranslations lang msg ->
210216 ["lang" .= Text.pack lang,
211217 "message" .= Text.pack msg]
218+ UnexpectedXmlElement element parent ->
219+ ["element" .= Text.pack element,
220+ "parent" .= Text.pack parent]
212221
213222
214223showPos :: SourcePos -> String
@@ -259,6 +268,8 @@ showLogMessage msg =
259268 "Not rendering " ++ show bl
260269 DocxParserWarning s ->
261270 "Docx parser warning: " ++ s
271+ IgnoredIOError s ->
272+ "IO Error (ignored): " ++ s
262273 CouldNotFetchResource fp s ->
263274 "Could not fetch resource '" ++ fp ++ "'" ++
264275 if null s then "" else ": " ++ s
@@ -303,6 +314,8 @@ showLogMessage msg =
303314 CouldNotLoadTranslations lang m ->
304315 "Could not load translations for " ++ lang ++
305316 if null m then "" else '\n' : m
317+ UnexpectedXmlElement element parent ->
318+ "Unexpected XML element " ++ element ++ " in " ++ parent
306319
307320messageVerbosity:: LogMessage -> Verbosity
308321messageVerbosity msg =
@@ -324,6 +337,7 @@ messageVerbosity msg =
324337 InlineNotRendered{} -> INFO
325338 BlockNotRendered{} -> INFO
326339 DocxParserWarning{} -> INFO
340+ IgnoredIOError{} -> WARNING
327341 CouldNotFetchResource{} -> WARNING
328342 CouldNotDetermineImageSize{} -> WARNING
329343 CouldNotConvertImage{} -> WARNING
@@ -340,3 +354,4 @@ messageVerbosity msg =
340354 Deprecated{} -> WARNING
341355 NoTranslation{} -> WARNING
342356 CouldNotLoadTranslations{} -> WARNING
357+ UnexpectedXmlElement {} -> WARNING
src/Text/Pandoc/Lua.hs+5−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017–2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -31,13 +32,14 @@ module Text.Pandoc.Lua
3132 , runPandocLua
3233 ) where
3334
35+import Prelude
3436import Control.Monad ((>=>))
3537import Foreign.Lua (FromLuaStack (peek), Lua, LuaException (..),
3638 Status (OK), ToLuaStack (push))
3739import Text.Pandoc.Class (PandocIO)
3840import Text.Pandoc.Definition (Pandoc)
3941import Text.Pandoc.Lua.Filter (LuaFilter, walkMWithLuaFilter)
40−import Text.Pandoc.Lua.Init (runPandocLua)
42+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
4143import Text.Pandoc.Lua.Util (popValue)
4244import Text.Pandoc.Options (ReaderOptions)
4345import qualified Foreign.Lua as Lua
@@ -55,11 +57,12 @@ runLuaFilter' :: ReaderOptions -> FilePath -> String
5557runLuaFilter' ropts filterPath format pd = do
5658 registerFormat
5759 registerReaderOptions
60+ registerScriptPath filterPath
5861 top <- Lua.gettop
5962 stat <- Lua.dofile filterPath
6063 if stat /= OK
6164 then do
62− luaErrMsg <- peek (-1) <* Lua.pop 1
65+ luaErrMsg <- popValue
6366 Lua.throwLuaError luaErrMsg
6467 else do
6568 newtop <- Lua.gettop
src/Text/Pandoc/Lua/Filter.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleContexts #-}
23
34module Text.Pandoc.Lua.Filter ( LuaFilterFunction
@@ -10,6 +11,7 @@ module Text.Pandoc.Lua.Filter ( LuaFilterFunction
1011 , blockElementNames
1112 , inlineElementNames
1213 ) where
14+import Prelude
1315import Control.Monad (mplus, unless, when, (>=>))
1416import Control.Monad.Catch (finally)
1517import Text.Pandoc.Definition
src/Text/Pandoc/Lua/Init.hs+9−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -31,8 +32,10 @@ module Text.Pandoc.Lua.Init
3132 , runPandocLua
3233 , initLuaState
3334 , luaPackageParams
35+ , registerScriptPath
3436 ) where
3537
38+import Prelude
3639import Control.Monad.Trans (MonadIO (..))
3740import Data.Data (Data, dataTypeConstrs, dataTypeOf, showConstr)
3841import Data.IORef (newIORef, readIORef)
@@ -88,6 +91,11 @@ initLuaState luaPkgParams = do
8891 loadScriptFromDataDir (luaPkgDataDir luaPkgParams) "init.lua"
8992 putConstructorsInRegistry
9093
94+registerScriptPath :: FilePath -> Lua ()
95+registerScriptPath fp = do
96+ Lua.push fp
97+ Lua.setglobal "PANDOC_SCRIPT_FILE"
98+
9199putConstructorsInRegistry :: Lua ()
92100putConstructorsInRegistry = do
93101 Lua.getglobal "pandoc"
@@ -101,7 +109,7 @@ putConstructorsInRegistry = do
101109 Lua.pop 1
102110 where
103111 constrsToReg :: Data a => a -> Lua ()
104− constrsToReg = mapM_ putInReg . map showConstr . dataTypeConstrs . dataTypeOf
112+ constrsToReg = mapM_ (putInReg . showConstr) . dataTypeConstrs . dataTypeOf
105113
106114 putInReg :: String -> Lua ()
107115 putInReg name = do
src/Text/Pandoc/Lua/Module/MediaBag.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -29,6 +30,7 @@ module Text.Pandoc.Lua.Module.MediaBag
2930 ( pushModule
3031 ) where
3132
33+import Prelude
3234import Control.Monad (zipWithM_)
3335import Data.IORef (IORef, modifyIORef', readIORef)
3436import Data.Maybe (fromMaybe)
src/Text/Pandoc/Lua/Module/Pandoc.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -30,6 +31,7 @@ module Text.Pandoc.Lua.Module.Pandoc
3031 ( pushModule
3132 ) where
3233
34+import Prelude
3335import Control.Monad (when)
3436import Data.Default (Default (..))
3537import Data.Maybe (fromMaybe)
src/Text/Pandoc/Lua/Module/Utils.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -29,6 +30,7 @@ module Text.Pandoc.Lua.Module.Utils
2930 ( pushModule
3031 ) where
3132
33+import Prelude
3234import Control.Applicative ((<|>))
3335import Data.Default (def)
3436import Foreign.Lua (FromLuaStack, Lua, LuaInteger, NumResults)
src/Text/Pandoc/Lua/Packages.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -32,6 +33,7 @@ module Text.Pandoc.Lua.Packages
3233 , installPandocPackageSearcher
3334 ) where
3435
36+import Prelude
3537import Control.Monad (forM_)
3638import Data.ByteString.Char8 (unpack)
3739import Data.IORef (IORef)
src/Text/Pandoc/Lua/StackInstances.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
34 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ StackValue instances for pandoc types.
3334-}
3435module Text.Pandoc.Lua.StackInstances () where
3536
37+import Prelude
3638import Control.Applicative ((<|>))
3739import Control.Monad (when)
3840import Control.Monad.Catch (finally)
src/Text/Pandoc/Lua/Util.hs+3−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright © 2012-2018 John MacFarlane <jgm@berkeley.edu>
34 2017-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -46,6 +47,7 @@ module Text.Pandoc.Lua.Util
4647 , dostring'
4748 ) where
4849
50+import Prelude
4951import Control.Monad (when)
5052import Control.Monad.Catch (finally)
5153import Data.ByteString.Char8 (unpack)
@@ -132,7 +134,7 @@ class PushViaCall a where
132134instance PushViaCall (Lua ()) where
133135 pushViaCall' fn pushArgs num = do
134136 Lua.push fn
135− Lua.rawget (Lua.registryindex)
137+ Lua.rawget Lua.registryindex
136138 pushArgs
137139 call num 1
138140
src/Text/Pandoc/MIME.hs+3−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ Mime type lookup for ODT writer.
2930-}
3031module Text.Pandoc.MIME ( MimeType, getMimeType, getMimeTypeDef,
3132 extensionFromMimeType )where
33+import Prelude
3234import Data.Char (toLower)
3335import Data.List (isPrefixOf, isSuffixOf)
3436import qualified Data.Map as M
@@ -172,7 +174,7 @@ mimeTypesList = -- List borrowed from happstack-server.
172174 ,("eml","message/rfc822")
173175 ,("ent","chemical/x-ncbi-asn1-ascii")
174176 ,("eot","application/vnd.ms-fontobject")
175− ,("eps","application/postscript")
177+ ,("eps","application/eps")
176178 ,("etx","text/x-setext")
177179 ,("exe","application/x-msdos-program")
178180 ,("ez","application/andrew-inset")
src/Text/Pandoc/MediaBag.hs+4−1
@@ -1,3 +1,5 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
13{-# LANGUAGE DeriveDataTypeable #-}
24{-# LANGUAGE GeneralizedNewtypeDeriving #-}
35{-
@@ -36,6 +38,7 @@ module Text.Pandoc.MediaBag (
3638 insertMedia,
3739 mediaDirectory,
3840 ) where
41+import Prelude
3942import qualified Data.ByteString.Lazy as BL
4043import Data.Data (Data)
4144import qualified Data.Map as M
@@ -50,7 +53,7 @@ import Text.Pandoc.MIME (MimeType, getMimeTypeDef)
5053-- can be used for an empty 'MediaBag', and '<>' can be used to append
5154-- two 'MediaBag's.
5255newtype MediaBag = MediaBag (M.Map [String] (MimeType, BL.ByteString))
53− deriving (Monoid, Data, Typeable)
56+ deriving (Semigroup, Monoid, Data, Typeable)
5457
5558instance Show MediaBag where
5659 show bag = "MediaBag " ++ show (mediaDirectory bag)
src/Text/Pandoc/Options.hs+2−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE DeriveDataTypeable #-}
23{-# LANGUAGE DeriveGeneric #-}
34{-# LANGUAGE TemplateHaskell #-}
@@ -46,6 +47,7 @@ module Text.Pandoc.Options ( module Text.Pandoc.Extensions
4647 , def
4748 , isEnabled
4849 ) where
50+import Prelude
4951import Data.Aeson (defaultOptions)
5052import Data.Aeson.TH (deriveJSON)
5153import Data.Data (Data)
@@ -104,9 +106,6 @@ defaultAbbrevs = Set.fromList
104106data EPUBVersion = EPUB2 | EPUB3 deriving (Eq, Show, Read, Data, Typeable, Generic)
105107
106108data HTMLMathMethod = PlainMath
107− | LaTeXMathML (Maybe String) -- url of LaTeXMathML.js
108− | JsMath (Maybe String) -- url of jsMath load script
109− | GladTeX
110109 | WebTeX String -- url of TeX->image script.
111110 | MathML
112111 | MathJax String -- url of MathJax.js
src/Text/Pandoc/PDF.hs+26−11
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -32,6 +33,7 @@ Conversion of LaTeX documents to PDF.
3233-}
3334module Text.Pandoc.PDF ( makePDF ) where
3435
36+import Prelude
3537import qualified Codec.Picture as JP
3638import qualified Control.Exception as E
3739import Control.Monad (unless, when)
@@ -41,10 +43,8 @@ import Data.ByteString.Lazy (ByteString)
4143import qualified Data.ByteString.Lazy as BL
4244import qualified Data.ByteString.Lazy.Char8 as BC
4345import Data.Maybe (fromMaybe)
44−import Data.Monoid ((<>))
4546import Data.Text (Text)
4647import qualified Data.Text as T
47−import qualified Data.Text.IO as TextIO
4848import System.Directory
4949import System.Environment
5050import System.Exit (ExitCode (..))
@@ -61,7 +61,7 @@ import Text.Pandoc.Error (PandocError (PandocPDFProgramNotFoundError))
6161import Text.Pandoc.MIME (getMimeType)
6262import Text.Pandoc.Options (HTMLMathMethod (..), WriterOptions (..))
6363import Text.Pandoc.Process (pipeProcess)
64−import Text.Pandoc.Shared (inDirectory, stringify, withTempDir)
64+import Text.Pandoc.Shared (inDirectory, stringify)
6565import qualified Text.Pandoc.UTF8 as UTF8
6666import Text.Pandoc.Walk (walkM)
6767import Text.Pandoc.Writers.Shared (getField, metaToJSON)
@@ -127,9 +127,11 @@ makePDF "pdfroff" pdfargs writer opts doc = do
127127 verbosity <- getVerbosity
128128 liftIO $ ms2pdf verbosity args source
129129makePDF program pdfargs writer opts doc = do
130− let withTemp = if takeBaseName program == "context"
131− then withTempDirectory "."
132− else withTempDir
130+ -- With context and latex, we create a temp directory within
131+ -- the working directory, since pdflatex sometimes tries to
132+ -- use tools like epstopdf.pl, which are restricted if run
133+ -- on files outside the working directory.
134+ let withTemp = withTempDirectory "."
133135 commonState <- getCommonState
134136 verbosity <- getVerbosity
135137 liftIO $ withTemp "tex2pdf." $ \tmpdir -> do
@@ -170,6 +172,8 @@ convertImage tmpdir fname =
170172 Just "image/png" -> doNothing
171173 Just "image/jpeg" -> doNothing
172174 Just "application/pdf" -> doNothing
175+ -- Note: eps is converted by pdflatex using epstopdf.pl
176+ Just "application/eps" -> doNothing
173177 Just "image/svg+xml" -> E.catch (do
174178 (exit, _) <- pipeProcess Nothing "rsvg-convert"
175179 ["-f","pdf","-a","-o",pdfOut,fname] BL.empty
@@ -274,7 +278,12 @@ runTeXProgram verbosity program args runNumber numRuns tmpDir source = do
274278 let file' = file
275279#endif
276280 let programArgs = ["-halt-on-error", "-interaction", "nonstopmode",
277− "-output-directory", tmpDir'] ++ args ++ [file']
281+ "-output-directory", tmpDir'] ++
282+ -- see #4484, only compress images on last run:
283+ if program == "xelatex" && runNumber < numRuns
284+ then ["-output-driver", "xdvipdfmx -z0"]
285+ else []
286+ ++ args ++ [file']
278287 env' <- getEnvironment
279288 let sep = [searchPathSeparator]
280289 let texinputs = maybe (tmpDir' ++ sep) ((tmpDir' ++ sep) ++)
@@ -354,9 +363,14 @@ html2pdf :: Verbosity -- ^ Verbosity level
354363 -> Text -- ^ HTML5 source
355364 -> IO (Either ByteString ByteString)
356365html2pdf verbosity program args source = do
366+ -- write HTML to temp file so we don't have to rewrite
367+ -- all links in `a`, `img`, `style`, `script`, etc. tags,
368+ -- and piping to weasyprint didn't work on Windows either.
369+ file <- withTempFile "." "html2pdf.html" $ \fp _ -> return fp
357370 pdfFile <- withTempFile "." "html2pdf.pdf" $ \fp _ -> return fp
371+ BS.writeFile file $ UTF8.fromText source
358372 let pdfFileArgName = ["-o" | program == "prince"]
359− let programArgs = args ++ ["-"] ++ pdfFileArgName ++ [pdfFile]
373+ let programArgs = args ++ [file] ++ pdfFileArgName ++ [pdfFile]
360374 env' <- getEnvironment
361375 when (verbosity >= INFO) $ do
362376 putStrLn "[makePDF] Command line:"
@@ -365,15 +379,16 @@ html2pdf verbosity program args source = do
365379 putStrLn "[makePDF] Environment:"
366380 mapM_ print env'
367381 putStr "\n"
368− putStrLn "[makePDF] Contents of intermediate HTML:"
369− TextIO.putStr source
382+ putStrLn $ "[makePDF] Contents of " ++ file ++ ":"
383+ BL.readFile file >>= BL.putStr
370384 putStr "\n"
371385 (exit, out) <- E.catch
372− (pipeProcess (Just env') program programArgs $ BL.fromStrict $ UTF8.fromText source)
386+ (pipeProcess (Just env') program programArgs BL.empty)
373387 (\(e :: IOError) -> if isDoesNotExistError e
374388 then E.throwIO $
375389 PandocPDFProgramNotFoundError program
376390 else E.throwIO e)
391+ removeFile file
377392 when (verbosity >= INFO) $ do
378393 BL.hPutStr stdout out
379394 putStr "\n"
src/Text/Pandoc/Parsing.hs+13−10
@@ -1,3 +1,5 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
13{-# LANGUAGE ExplicitForAll #-}
24{-# LANGUAGE FlexibleContexts #-}
35{-# LANGUAGE FlexibleInstances #-}
@@ -133,7 +135,7 @@ module Text.Pandoc.Parsing ( takeWhileP,
133135 extractIdClass,
134136 insertIncludedFile,
135137 insertIncludedFileF,
136− -- * Re-exports from Text.Pandoc.Parsec
138+ -- * Re-exports from Text.Parsec
137139 Stream,
138140 runParser,
139141 runParserT,
@@ -194,6 +196,7 @@ module Text.Pandoc.Parsing ( takeWhileP,
194196 )
195197where
196198
199+import Prelude
197200import Control.Monad.Identity
198201import Control.Monad.Reader
199202import Data.Char (chr, isAlphaNum, isAscii, isAsciiUpper, isHexDigit,
@@ -202,7 +205,6 @@ import Data.Default
202205import Data.List (intercalate, isSuffixOf, transpose)
203206import qualified Data.Map as M
204207import Data.Maybe (mapMaybe, fromMaybe)
205−import Data.Monoid ((<>))
206208import qualified Data.Set as Set
207209import Data.Text (Text)
208210import Text.HTML.TagSoup.Entity (lookupEntity)
@@ -250,10 +252,11 @@ returnF = return . return
250252trimInlinesF :: Future s Inlines -> Future s Inlines
251253trimInlinesF = liftM trimInlines
252254
253−instance Monoid a => Monoid (Future s a) where
255+instance Semigroup a => Semigroup (Future s a) where
256+ (<>) = liftM2 (<>)
257+instance (Semigroup a, Monoid a) => Monoid (Future s a) where
254258 mempty = return mempty
255− mappend = liftM2 mappend
256− mconcat = liftM mconcat . sequence
259+ mappend = (<>)
257260
258261-- | Parse characters while a predicate is true.
259262takeWhileP :: Monad m
@@ -529,15 +532,15 @@ romanNumeral upperCase = do
529532 map char romanDigits
530533 thousands <- ((1000 *) . length) <$> many thousand
531534 ninehundreds <- option 0 $ try $ hundred >> thousand >> return 900
532− fivehundreds <- ((500 *) . length) <$> many fivehundred
535+ fivehundreds <- option 0 $ 500 <$ fivehundred
533536 fourhundreds <- option 0 $ try $ hundred >> fivehundred >> return 400
534537 hundreds <- ((100 *) . length) <$> many hundred
535538 nineties <- option 0 $ try $ ten >> hundred >> return 90
536− fifties <- ((50 *) . length) <$> many fifty
539+ fifties <- option 0 $ (50 <$ fifty)
537540 forties <- option 0 $ try $ ten >> fifty >> return 40
538541 tens <- ((10 *) . length) <$> many ten
539542 nines <- option 0 $ try $ one >> ten >> return 9
540− fives <- ((5 *) . length) <$> many five
543+ fives <- option 0 $ (5 <$ five)
541544 fours <- option 0 $ try $ one >> five >> return 4
542545 ones <- length <$> many one
543546 let total = thousands + ninehundreds + fivehundreds + fourhundreds +
@@ -590,7 +593,7 @@ uri = try $ do
590593 -- http://en.wikipedia.org/wiki/State_of_emergency_(disambiguation)
591594 -- as a URL, while NOT picking up the closing paren in
592595 -- (http://wikipedia.org). So we include balanced parens in the URL.
593− let isWordChar c = isAlphaNum c || c `elem` "#$%*+/@\\_-&="
596+ let isWordChar c = isAlphaNum c || c `elem` "#$%+/@\\_-&="
594597 let wordChar = satisfy isWordChar
595598 let percentEscaped = try $ char '%' >> skipMany1 (satisfy isHexDigit)
596599 let entity = () <$ characterReference
@@ -1437,7 +1440,7 @@ token pp pos match = tokenPrim pp (\_ t _ -> pos t) match
14371440
14381441infixr 5 <+?>
14391442(<+?>) :: (Monoid a) => ParserT s st m a -> ParserT s st m a -> ParserT s st m a
1440−a <+?> b = a >>= flip fmap (try b <|> return mempty) . (<>)
1443+a <+?> b = a >>= flip fmap (try b <|> return mempty) . mappend
14411444
14421445extractIdClass :: Attr -> Attr
14431446extractIdClass (ident, cls, kvs) = (ident', cls', kvs')
src/Text/Pandoc/Pretty.hs+3−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE GeneralizedNewtypeDeriving #-}
34{-
@@ -77,12 +78,12 @@ module Text.Pandoc.Pretty (
7778 )
7879
7980where
81+import Prelude
8082import Control.Monad
8183import Control.Monad.State.Strict
8284import Data.Char (isSpace)
8385import Data.Foldable (toList)
8486import Data.List (intersperse)
85−import Data.Monoid ((<>))
8687import Data.Sequence (Seq, ViewL (..), fromList, mapWithIndex, singleton, viewl,
8788 (<|))
8889import qualified Data.Sequence as Seq
@@ -112,7 +113,7 @@ data D = Text Int String
112113 deriving (Show, Eq)
113114
114115newtype Doc = Doc { unDoc :: Seq D }
115− deriving (Monoid, Show, Eq)
116+ deriving (Semigroup, Monoid, Show, Eq)
116117
117118instance IsString Doc where
118119 fromString = text
src/Text/Pandoc/Process.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ ByteString variant of 'readProcessWithExitCode'.
2930-}
3031module Text.Pandoc.Process (pipeProcess)
3132where
33+import Prelude
3234import Control.Concurrent (forkIO, newEmptyMVar, putMVar, takeMVar)
3335import Control.Exception
3436import Control.Monad (unless)
src/Text/Pandoc/Readers.hs+7−2
@@ -1,6 +1,7 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE GADTs #-}
1+{-# LANGUAGE MonoLocalBinds #-}
2+{-# LANGUAGE NoImplicitPrelude #-}
33{-# LANGUAGE ScopedTypeVariables #-}
4+
45{-
56Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
67
@@ -64,11 +65,13 @@ module Text.Pandoc.Readers
6465 , readTxt2Tags
6566 , readEPUB
6667 , readMuse
68+ , readFB2
6769 -- * Miscellaneous
6870 , getReader
6971 , getDefaultExtensions
7072 ) where
7173
74+import Prelude
7275import Control.Monad.Except (throwError)
7376import Data.Aeson
7477import qualified Data.ByteString.Lazy as BL
@@ -84,6 +87,7 @@ import Text.Pandoc.Readers.Creole
8487import Text.Pandoc.Readers.DocBook
8588import Text.Pandoc.Readers.Docx
8689import Text.Pandoc.Readers.EPUB
90+import Text.Pandoc.Readers.FB2
8791import Text.Pandoc.Readers.Haddock
8892import Text.Pandoc.Readers.HTML (readHtml)
8993import Text.Pandoc.Readers.JATS (readJATS)
@@ -143,6 +147,7 @@ readers = [ ("native" , TextReader readNative)
143147 ,("epub" , ByteStringReader readEPUB)
144148 ,("muse" , TextReader readMuse)
145149 ,("man" , TextReader readMan)
150+ ,("fb2" , TextReader readFB2)
146151 ]
147152
148153-- | Retrieve reader, extensions based on formatSpec (format+extensions).
src/Text/Pandoc/Readers/CommonMark.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -32,6 +33,7 @@ CommonMark is a strongly specified variant of Markdown: http://commonmark.org.
3233module Text.Pandoc.Readers.CommonMark (readCommonMark)
3334where
3435
36+import Prelude
3537import CMarkGFM
3638import Control.Monad.State
3739import Data.Char (isAlphaNum, isLetter, isSpace, toLower)
src/Text/Pandoc/Readers/Creole.hs+3−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23 Copyright (C) 2017 Sascha Wilde <wilde@sha-bang.de>
34
@@ -35,10 +36,10 @@ Conversion of creole text to 'Pandoc' document.
3536module Text.Pandoc.Readers.Creole ( readCreole
3637 ) where
3738
39+import Prelude
3840import Control.Monad.Except (guard, liftM2, throwError)
3941import qualified Data.Foldable as F
4042import Data.Maybe (fromMaybe)
41−import Data.Monoid
4243import Data.Text (Text)
4344import qualified Data.Text as T
4445import qualified Text.Pandoc.Builder as B
@@ -67,7 +68,7 @@ type CRLParser = ParserT [Char] ParserState
6768-- Utility functions
6869--
6970
70−(<+>) :: (Monad m, Monoid a) => m a -> m a -> m a
71+(<+>) :: (Monad m, Semigroup a) => m a -> m a -> m a
7172(<+>) = liftM2 (<>)
7273
7374-- we have to redefine `enclosed' from Text.Pandoc.Parsing, because it
src/Text/Pandoc/Readers/DocBook.hs+80−12
@@ -1,5 +1,35 @@
1−{-# LANGUAGE ExplicitForAll #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-
3+Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.Readers.DocBook
22+ Copyright : Copyright (C) 2006-2018 John MacFarlane
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : John MacFarlane <jgm@berkeley.edu>
26+ Stability : alpha
27+ Portability : portable
28+
29+Conversion of DocBook XML to 'Pandoc' document.
30+-}
231module Text.Pandoc.Readers.DocBook ( readDocBook ) where
32+import Prelude
333import Control.Monad.State.Strict
434import Data.Char (isSpace, toUpper)
535import Data.Default
@@ -235,7 +265,7 @@ List of all DocBook tags, with [x] indicating implemented,
235265[ ] manvolnum - A reference volume number
236266[x] markup - A string of formatting markup in text that is to be
237267 represented literally
238−[ ] mathphrase - A mathematical phrase, an expression that can be represented
268+[x] mathphrase - A mathematical phrase, an expression that can be represented
239269 with ordinary text and a small amount of markup
240270[ ] medialabel - A name that identifies the physical medium on which some
241271 information resides
@@ -697,6 +727,8 @@ parseBlock (Elem e) =
697727 "bibliodiv" -> sect 1
698728 "biblioentry" -> parseMixed para (elContent e)
699729 "bibliomixed" -> parseMixed para (elContent e)
730+ "equation" -> para <$> equation e displayMath
731+ "informalequation" -> para <$> equation e displayMath
700732 "glosssee" -> para . (\ils -> text "See " <> ils <> str ".")
701733 <$> getInlines e
702734 "glossseealso" -> para . (\ils -> text "See also " <> ils <> str ".")
@@ -923,9 +955,9 @@ parseInline (CRef ref) =
923955 return $ maybe (text $ map toUpper ref) text $ lookupEntity ref
924956parseInline (Elem e) =
925957 case qName (elName e) of
926− "equation" -> equation displayMath
927− "informalequation" -> equation displayMath
928− "inlineequation" -> equation math
958+ "equation" -> equation e displayMath
959+ "informalequation" -> equation e displayMath
960+ "inlineequation" -> equation e math
929961 "subscript" -> subscript <$> innerInlines
930962 "superscript" -> superscript <$> innerInlines
931963 "inlinemediaobject" -> getMediaobject e
@@ -1004,13 +1036,6 @@ parseInline (Elem e) =
10041036 _ -> innerInlines
10051037 where innerInlines = (trimInlines . mconcat) <$>
10061038 mapM parseInline (elContent e)
1007− equation constructor = return $ mconcat $
1008− map (constructor . writeTeX)
1009− $ rights
1010− $ map (readMathML . showElement . everywhere (mkT removePrefix))
1011− $ filterChildren (\x -> qName (elName x) == "math" &&
1012− qPrefix (elName x) == Just "mml") e
1013− removePrefix elname = elname { qPrefix = Nothing }
10141039 codeWithLang = do
10151040 let classes' = case attrValue "language" e of
10161041 "" -> []
@@ -1048,6 +1073,7 @@ parseInline (Elem e) =
10481073 | not (null xrefLabel) = xrefLabel
10491074 | otherwise = case qName (elName el) of
10501075 "chapter" -> descendantContent "title" el
1076+ "section" -> descendantContent "title" el
10511077 "sect1" -> descendantContent "title" el
10521078 "sect2" -> descendantContent "title" el
10531079 "sect3" -> descendantContent "title" el
@@ -1060,3 +1086,45 @@ parseInline (Elem e) =
10601086 xrefLabel = attrValue "xreflabel" el
10611087 descendantContent name = maybe "???" strContent
10621088 . filterElementName (\n -> qName n == name)
1089+
1090+-- | Extract a math equation from an element
1091+--
1092+-- asciidoc can generate Latex math in CDATA sections.
1093+--
1094+-- Note that if some MathML can't be parsed it is silently ignored!
1095+equation
1096+ :: Monad m
1097+ => Element
1098+ -- ^ The element from which to extract a mathematical equation
1099+ -> (String -> Inlines)
1100+ -- ^ A constructor for some Inlines, taking the TeX code as input
1101+ -> m Inlines
1102+equation e constructor =
1103+ return $ mconcat $ map constructor $ mathMLEquations ++ latexEquations
1104+ where
1105+ mathMLEquations :: [String]
1106+ mathMLEquations = map writeTeX $ rights $ readMath
1107+ (\x -> qName (elName x) == "math" && qPrefix (elName x) == Just "mml")
1108+ (readMathML . showElement)
1109+
1110+ latexEquations :: [String]
1111+ latexEquations = readMath (\x -> qName (elName x) == "mathphrase")
1112+ (concat . fmap showVerbatimCData . elContent)
1113+
1114+ readMath :: (Element -> Bool) -> (Element -> b) -> [b]
1115+ readMath childPredicate fromElement =
1116+ ( map (fromElement . everywhere (mkT removePrefix))
1117+ $ filterChildren childPredicate e
1118+ )
1119+
1120+-- | Get the actual text stored in a verbatim CData block. 'showContent'
1121+-- returns the text still surrounded by the [[CDATA]] tags.
1122+--
1123+-- Returns 'showContent' if this is not a verbatim CData
1124+showVerbatimCData :: Content -> String
1125+showVerbatimCData (Text (CData CDataVerbatim d _)) = d
1126+showVerbatimCData c = showContent c
1127+
1128+-- | Set the prefix of a name to 'Nothing'
1129+removePrefix :: QName -> QName
1130+removePrefix elname = elname { qPrefix = Nothing }
src/Text/Pandoc/Readers/Docx.hs+70−84
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE PatternGuards #-}
@@ -74,6 +75,7 @@ module Text.Pandoc.Readers.Docx
7475 ( readDocx
7576 ) where
7677
78+import Prelude
7779import Codec.Archive.Zip
7880import Control.Monad.Reader
7981import Control.Monad.State.Strict
@@ -122,7 +124,6 @@ data DState = DState { docxAnchorMap :: M.Map String String
122124 , docxImmedPrevAnchor :: Maybe String
123125 , docxMediaBag :: MediaBag
124126 , docxDropCap :: Inlines
125− , docxWarnings :: [String]
126127 -- keep track of (numId, lvl) values for
127128 -- restarting
128129 , docxListState :: M.Map (String, String) Integer
@@ -135,18 +136,16 @@ instance Default DState where
135136 , docxImmedPrevAnchor = Nothing
136137 , docxMediaBag = mempty
137138 , docxDropCap = mempty
138− , docxWarnings = []
139139 , docxListState = M.empty
140140 , docxPrevPara = mempty
141141 }
142142
143143data DEnv = DEnv { docxOptions :: ReaderOptions
144144 , docxInHeaderBlock :: Bool
145− , docxCustomStyleAlready :: Bool
146145 }
147146
148147instance Default DEnv where
149− def = DEnv def False False
148+ def = DEnv def False
150149
151150type DocxContext m = ReaderT DEnv (StateT DState m)
152151
@@ -252,103 +251,88 @@ parPartToString _ = ""
252251blacklistedCharStyles :: [String]
253252blacklistedCharStyles = ["Hyperlink"]
254253
255−resolveDependentRunStyle :: RunStyle -> RunStyle
254+resolveDependentRunStyle :: PandocMonad m => RunStyle -> DocxContext m RunStyle
256255resolveDependentRunStyle rPr
257256 | Just (s, _) <- rStyle rPr, s `elem` blacklistedCharStyles =
258− rPr
259− | Just (_, cs) <- rStyle rPr =
260− let rPr' = resolveDependentRunStyle cs
261− in
262− RunStyle { isBold = case isBold rPr of
263− Just bool -> Just bool
264− Nothing -> isBold rPr'
265− , isItalic = case isItalic rPr of
266− Just bool -> Just bool
267− Nothing -> isItalic rPr'
268− , isSmallCaps = case isSmallCaps rPr of
269− Just bool -> Just bool
270− Nothing -> isSmallCaps rPr'
271− , isStrike = case isStrike rPr of
272− Just bool -> Just bool
273− Nothing -> isStrike rPr'
274− , rVertAlign = case rVertAlign rPr of
275− Just valign -> Just valign
276− Nothing -> rVertAlign rPr'
277− , rUnderline = case rUnderline rPr of
278− Just ulstyle -> Just ulstyle
279− Nothing -> rUnderline rPr'
280− , rStyle = rStyle rPr }
281− | otherwise = rPr
282−
283−extraRunStyleInfo :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
284−extraRunStyleInfo rPr
285− | Just (s, _) <- rStyle rPr = do
286− already <- asks docxCustomStyleAlready
257+ return rPr
258+ | Just (_, cs) <- rStyle rPr = do
287259 opts <- asks docxOptions
288− return $ if isEnabled Ext_styles opts && not already
289− then spanWith ("", [], [("custom-style", s)])
290− else id
291− | otherwise = return id
260+ if isEnabled Ext_styles opts
261+ then return rPr
262+ else do rPr' <- resolveDependentRunStyle cs
263+ return $
264+ RunStyle { isBold = case isBold rPr of
265+ Just bool -> Just bool
266+ Nothing -> isBold rPr'
267+ , isItalic = case isItalic rPr of
268+ Just bool -> Just bool
269+ Nothing -> isItalic rPr'
270+ , isSmallCaps = case isSmallCaps rPr of
271+ Just bool -> Just bool
272+ Nothing -> isSmallCaps rPr'
273+ , isStrike = case isStrike rPr of
274+ Just bool -> Just bool
275+ Nothing -> isStrike rPr'
276+ , rVertAlign = case rVertAlign rPr of
277+ Just valign -> Just valign
278+ Nothing -> rVertAlign rPr'
279+ , rUnderline = case rUnderline rPr of
280+ Just ulstyle -> Just ulstyle
281+ Nothing -> rUnderline rPr'
282+ , rStyle = rStyle rPr }
283+ | otherwise = return rPr
292284
293285runStyleToTransform :: PandocMonad m => RunStyle -> DocxContext m (Inlines -> Inlines)
294286runStyleToTransform rPr
295287 | Just (s, _) <- rStyle rPr
296288 , s `elem` spansToKeep = do
297− let rPr' = rPr{rStyle = Nothing}
298− transform <- runStyleToTransform rPr'
289+ transform <- runStyleToTransform rPr{rStyle = Nothing}
299290 return $ spanWith ("", [s], []) . transform
291+ | Just (s, _) <- rStyle rPr = do
292+ opts <- asks docxOptions
293+ let extraInfo = if isEnabled Ext_styles opts
294+ then spanWith ("", [], [("custom-style", s)])
295+ else id
296+ transform <- runStyleToTransform rPr{rStyle = Nothing}
297+ return $ extraInfo . transform
300298 | Just True <- isItalic rPr = do
301− extraInfo <- extraRunStyleInfo rPr
302− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
303− runStyleToTransform rPr {isItalic = Nothing}
304− return $ extraInfo . emph . transform
299+ transform <- runStyleToTransform rPr{isItalic = Nothing}
300+ return $ emph . transform
305301 | Just True <- isBold rPr = do
306− extraInfo <- extraRunStyleInfo rPr
307− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
308− runStyleToTransform rPr {isBold = Nothing}
309− return $ extraInfo . strong . transform
302+ transform <- runStyleToTransform rPr{isBold = Nothing}
303+ return $ strong . transform
310304 | Just True <- isSmallCaps rPr = do
311− extraInfo <- extraRunStyleInfo rPr
312− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
313− runStyleToTransform rPr {isSmallCaps = Nothing}
314− return $ extraInfo . smallcaps . transform
305+ transform <- runStyleToTransform rPr{isSmallCaps = Nothing}
306+ return $ smallcaps . transform
315307 | Just True <- isStrike rPr = do
316− extraInfo <- extraRunStyleInfo rPr
317− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
318− runStyleToTransform rPr {isStrike = Nothing}
319− return $ extraInfo . strikeout . transform
308+ transform <- runStyleToTransform rPr{isStrike = Nothing}
309+ return $ strikeout . transform
320310 | Just SupScrpt <- rVertAlign rPr = do
321− extraInfo <- extraRunStyleInfo rPr
322− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
323− runStyleToTransform rPr {rVertAlign = Nothing}
324− return $ extraInfo . superscript . transform
311+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
312+ return $ superscript . transform
325313 | Just SubScrpt <- rVertAlign rPr = do
326− extraInfo <- extraRunStyleInfo rPr
327− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
328− runStyleToTransform rPr {rVertAlign = Nothing}
329− return $ extraInfo . subscript . transform
314+ transform <- runStyleToTransform rPr{rVertAlign = Nothing}
315+ return $ subscript . transform
330316 | Just "single" <- rUnderline rPr = do
331− extraInfo <- extraRunStyleInfo rPr
332− transform <- local (\e -> e{docxCustomStyleAlready = True}) $
333− runStyleToTransform rPr {rUnderline = Nothing}
334− return $ extraInfo . underlineSpan . transform
335− | otherwise = extraRunStyleInfo rPr
317+ transform <- runStyleToTransform rPr{rUnderline = Nothing}
318+ return $ underlineSpan . transform
319+ | otherwise = return id
336320
337321runToInlines :: PandocMonad m => Run -> DocxContext m Inlines
338322runToInlines (Run rs runElems)
339323 | Just (s, _) <- rStyle rs
340− , s `elem` codeStyles =
341− let rPr = resolveDependentRunStyle rs
342− codeString = code $ concatMap runElemToString runElems
343− in
344− return $ case rVertAlign rPr of
345− Just SupScrpt -> superscript codeString
346− Just SubScrpt -> subscript codeString
347− _ -> codeString
324+ , s `elem` codeStyles = do
325+ rPr <- resolveDependentRunStyle rs
326+ let codeString = code $ concatMap runElemToString runElems
327+ return $ case rVertAlign rPr of
328+ Just SupScrpt -> superscript codeString
329+ Just SubScrpt -> subscript codeString
330+ _ -> codeString
348331 | otherwise = do
349− let ils = smushInlines (map runElemToInlines runElems)
350− transform <- runStyleToTransform $ resolveDependentRunStyle rs
351− return $ transform ils
332+ rPr <- resolveDependentRunStyle rs
333+ let ils = smushInlines (map runElemToInlines runElems)
334+ transform <- runStyleToTransform rPr
335+ return $ transform ils
352336runToInlines (Footnote bps) = do
353337 blksList <- smushBlocks <$> mapM bodyPartToBlocks bps
354338 return $ note blksList
@@ -385,7 +369,7 @@ blocksToInlinesWarn cmtId blks = do
385369parPartToInlines :: PandocMonad m => ParPart -> DocxContext m Inlines
386370parPartToInlines parPart =
387371 case parPart of
388− (BookMark _ anchor) | notElem anchor dummyAnchors -> do
372+ (BookMark _ anchor) | anchor `notElem` dummyAnchors -> do
389373 inHdrBool <- asks docxInHeaderBlock
390374 ils <- parPartToInlines' parPart
391375 immedPrevAnchor <- gets docxImmedPrevAnchor
@@ -478,8 +462,6 @@ parPartToInlines' (ExternalHyperLink target runs) = do
478462 return $ link target "" ils
479463parPartToInlines' (PlainOMath exps) =
480464 return $ math $ writeTeX exps
481−parPartToInlines' (SmartTag runs) =
482− smushInlines <$> mapM runToInlines runs
483465parPartToInlines' (Field info runs) =
484466 case info of
485467 HyperlinkField url -> parPartToInlines' $ ExternalHyperLink url runs
@@ -706,6 +688,10 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
706688 rowLength :: Row -> Int
707689 rowLength (Row c) = length c
708690
691+ -- pad cells. New Text.Pandoc.Builder will do that for us,
692+ -- so this is for compatibility while we switch over.
693+ let cells' = map (\row -> take width (row ++ repeat mempty)) cells
694+
709695 hdrCells <- case hdr of
710696 Just r' -> rowToBlocksList r'
711697 Nothing -> return $ replicate width mempty
@@ -718,7 +704,7 @@ bodyPartToBlocks (Tbl cap _ look parts@(r:rs)) = do
718704 let alignments = replicate width AlignDefault
719705 widths = replicate width 0 :: [Double]
720706
721− return $ table caption (zip alignments widths) hdrCells cells
707+ return $ table caption (zip alignments widths) hdrCells cells'
722708bodyPartToBlocks (OMathPara e) =
723709 return $ para $ displayMath (writeTeX e)
724710
src/Text/Pandoc/Readers/Docx/Combine.hs+6
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE PatternGuards #-}
34{-# LANGUAGE TypeSynonymInstances #-}
@@ -7,6 +8,7 @@ module Text.Pandoc.Readers.Docx.Combine ( smushInlines
78 )
89 where
910
11+import Prelude
1012import Data.List
1113import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr, (><), (|>))
1214import qualified Data.Sequence as Seq (null)
@@ -133,6 +135,10 @@ combineBlocks bs cs
133135 | bs' :> BlockQuote bs'' <- viewr (unMany bs)
134136 , BlockQuote cs'' :< cs' <- viewl (unMany cs) =
135137 Many $ (bs' |> BlockQuote (bs'' <> cs'')) >< cs'
138+ | bs' :> CodeBlock attr codeStr <- viewr (unMany bs)
139+ , CodeBlock attr' codeStr' :< cs' <- viewl (unMany cs)
140+ , attr == attr' =
141+ Many $ (bs' |> CodeBlock attr (codeStr <> "\n" <> codeStr')) >< cs'
136142combineBlocks bs cs = bs <> cs
137143
138144instance (Monoid a, Eq a) => Eq (Modifier a) where
src/Text/Pandoc/Readers/Docx/Fields.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
34
@@ -32,6 +33,7 @@ module Text.Pandoc.Readers.Docx.Fields ( FieldInfo(..)
3233 , parseFieldInfo
3334 ) where
3435
36+import Prelude
3537import Text.Parsec
3638import Text.Parsec.String (Parser)
3739
src/Text/Pandoc/Readers/Docx/Lists.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
34
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Docx.Lists ( blocksToBullets
3334 , listParagraphDivs
3435 ) where
3536
37+import Prelude
3638import Data.List
3739import Data.Maybe
3840import Text.Pandoc.Generic (bottomUp)
src/Text/Pandoc/Readers/Docx/Parse.hs+13−14
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE PatternGuards #-}
34{-# LANGUAGE ViewPatterns #-}
@@ -58,6 +59,7 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..)
5859 , archiveToDocx
5960 , archiveToDocxWithWarnings
6061 ) where
62+import Prelude
6163import Codec.Archive.Zip
6264import Control.Applicative ((<|>))
6365import Control.Monad.Except
@@ -132,21 +134,23 @@ mapD f xs =
132134 in
133135 concatMapM handler xs
134136
135−unwrapSDT :: NameSpaces -> Content -> [Content]
136−unwrapSDT ns (Elem element)
137+unwrap :: NameSpaces -> Content -> [Content]
138+unwrap ns (Elem element)
137139 | isElem ns "w" "sdt" element
138140 , Just sdtContent <- findChildByName ns "w" "sdtContent" element
139− = map Elem $ elChildren sdtContent
140−unwrapSDT _ content = [content]
141+ = concatMap ((unwrap ns) . Elem) (elChildren sdtContent)
142+ | isElem ns "w" "smartTag" element
143+ = concatMap ((unwrap ns) . Elem) (elChildren element)
144+unwrap _ content = [content]
141145
142−unwrapSDTchild :: NameSpaces -> Content -> Content
143−unwrapSDTchild ns (Elem element) =
144− Elem $ element { elContent = concatMap (unwrapSDT ns) (elContent element) }
145−unwrapSDTchild _ content = content
146+unwrapChild :: NameSpaces -> Content -> Content
147+unwrapChild ns (Elem element) =
148+ Elem $ element { elContent = concatMap (unwrap ns) (elContent element) }
149+unwrapChild _ content = content
146150
147151walkDocument' :: NameSpaces -> XMLC.Cursor -> XMLC.Cursor
148152walkDocument' ns cur =
149− let modifiedCur = XMLC.modifyContent (unwrapSDTchild ns) cur
153+ let modifiedCur = XMLC.modifyContent (unwrapChild ns) cur
150154 in
151155 case XMLC.nextDF modifiedCur of
152156 Just cur' -> walkDocument' ns cur'
@@ -275,7 +279,6 @@ data ParPart = PlainRun Run
275279 | Drawing FilePath String String B.ByteString Extent -- title, alt
276280 | Chart -- placeholder for now
277281 | PlainOMath [Exp]
278− | SmartTag [Run]
279282 | Field FieldInfo [Run]
280283 | NullParPart -- when we need to return nothing, but
281284 -- not because of an error.
@@ -825,10 +828,6 @@ elemToParPart ns element
825828 | Just change <- getTrackedChange ns element = do
826829 runs <- mapD (elemToRun ns) (elChildren element)
827830 return $ ChangedRuns change runs
828−elemToParPart ns element
829− | isElem ns "w" "smartTag" element = do
830− runs <- mapD (elemToRun ns) (elChildren element)
831− return $ SmartTag runs
832831elemToParPart ns element
833832 | isElem ns "w" "bookmarkStart" element
834833 , Just bmId <- findAttrByName ns "w" "id" element
src/Text/Pandoc/Readers/Docx/StyleMap.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
23 , alterMap
34 , getMap
@@ -7,6 +8,7 @@ module Text.Pandoc.Readers.Docx.StyleMap ( StyleMaps(..)
78 , hasStyleName
89 ) where
910
11+import Prelude
1012import Control.Monad.State.Strict
1113import Data.Char (toLower)
1214import qualified Data.Map as M
src/Text/Pandoc/Readers/Docx/Util.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Text.Pandoc.Readers.Docx.Util (
23 NameSpaces
34 , elemName
@@ -8,6 +9,7 @@ module Text.Pandoc.Readers.Docx.Util (
89 , findAttrByName
910 ) where
1011
12+import Prelude
1113import Data.Maybe (mapMaybe)
1214import Text.XML.Light
1315
src/Text/Pandoc/Readers/EPUB.hs+35−7
@@ -1,12 +1,41 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−
3−{-# LANGUAGE TupleSections #-}
4−{-# LANGUAGE ViewPatterns #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE TupleSections #-}
3+{-# LANGUAGE ViewPatterns #-}
4+{-
5+Copyright (C) 2014-2018 Matthew Pickering
6+
7+This program is free software; you can redistribute it and/or modify
8+it under the terms of the GNU General Public License as published by
9+the Free Software Foundation; either version 2 of the License, or
10+(at your option) any later version.
11+
12+This program is distributed in the hope that it will be useful,
13+but WITHOUT ANY WARRANTY; without even the implied warranty of
14+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+GNU General Public License for more details.
16+
17+You should have received a copy of the GNU General Public License
18+along with this program; if not, write to the Free Software
19+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20+-}
21+
22+{- |
23+ Module : Text.Pandoc.Readers.EPUB
24+ Copyright : Copyright (C) 2014-2018 Matthew Pickering
25+ License : GNU GPL, version 2 or above
26+
27+ Maintainer : John MacFarlane <jgm@berkeley.edu>
28+ Stability : alpha
29+ Portability : portable
30+
31+Conversion of EPUB to 'Pandoc' document.
32+-}
533
634module Text.Pandoc.Readers.EPUB
735 (readEPUB)
836 where
937
38+import Prelude
1039import Codec.Archive.Zip (Archive (..), Entry, findEntryByPath, fromEntry,
1140 toArchiveOrFail)
1241import Control.DeepSeq (NFData, deepseq)
@@ -16,7 +45,6 @@ import qualified Data.ByteString.Lazy as BL (ByteString)
1645import Data.List (isInfixOf, isPrefixOf)
1746import qualified Data.Map as M (Map, elems, fromList, lookup)
1847import Data.Maybe (fromMaybe, mapMaybe)
19−import Data.Monoid ((<>))
2048import qualified Data.Text.Lazy as TL
2149import qualified Data.Text.Lazy.Encoding as TL
2250import Network.URI (unEscapeString)
@@ -93,7 +121,7 @@ fetchImages mimes root arc (query iq -> links) =
93121 mapM_ (uncurry3 insertMedia) (mapMaybe getEntry links)
94122 where
95123 getEntry link =
96− let abslink = normalise (root </> link) in
124+ let abslink = normalise (unEscapeString (root </> link)) in
97125 (link , lookup link mimes, ) . fromEntry
98126 <$> findEntryByPath abslink arc
99127
@@ -264,7 +292,7 @@ findAttrE :: PandocMonad m => QName -> Element -> m String
264292findAttrE q e = mkE "findAttr" $ findAttr q e
265293
266294findEntryByPathE :: PandocMonad m => FilePath -> Archive -> m Entry
267−findEntryByPathE (normalise -> path) a =
295+findEntryByPathE (normalise . unEscapeString -> path) a =
268296 mkE ("No entry on path: " ++ path) $ findEntryByPath path a
269297
270298parseXMLDocE :: PandocMonad m => String -> m Element
src/Text/Pandoc/Readers/FB2.hsnew file+404
@@ -0,0 +1,404 @@
1+{-# LANGUAGE FlexibleContexts #-}
2+{-# LANGUAGE TupleSections #-}
3+{-
4+Copyright (C) 2018 Alexander Krotov <ilabdsf@gmail.com>
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Readers.FB2
23+ Copyright : Copyright (C) 2018 Alexander Krotov
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : Alexander Krotov <ilabdsf@gmail.com>
27+ Stability : alpha
28+ Portability : portable
29+
30+Conversion of FB2 to 'Pandoc' document.
31+-}
32+
33+{-
34+
35+TODO:
36+ - Tables
37+ - Named styles
38+ - Parse ID attribute for all elements that have it
39+
40+-}
41+
42+module Text.Pandoc.Readers.FB2 ( readFB2 ) where
43+import Prelude
44+import Control.Monad.Except (throwError)
45+import Control.Monad.State.Strict
46+import Data.ByteString.Lazy.Char8 ( pack )
47+import Data.ByteString.Base64.Lazy
48+import Data.Char (isSpace, toUpper)
49+import Data.Functor
50+import Data.List (dropWhileEnd, intersperse)
51+import Data.List.Split (splitOn)
52+import Data.Text (Text)
53+import Data.Default
54+import Data.Maybe
55+import Text.HTML.TagSoup.Entity (lookupEntity)
56+import Text.Pandoc.Builder
57+import Text.Pandoc.Class (PandocMonad, insertMedia, report)
58+import Text.Pandoc.Error
59+import Text.Pandoc.Logging
60+import Text.Pandoc.Options
61+import Text.Pandoc.Shared (crFilter)
62+import Text.XML.Light
63+
64+type FB2 m = StateT FB2State m
65+
66+data FB2State = FB2State{ fb2SectionLevel :: Int
67+ , fb2Meta :: Meta
68+ , fb2Authors :: [String]
69+ } deriving Show
70+
71+instance Default FB2State where
72+ def = FB2State{ fb2SectionLevel = 1
73+ , fb2Meta = mempty
74+ , fb2Authors = []
75+ }
76+
77+instance HasMeta FB2State where
78+ setMeta field v s = s {fb2Meta = setMeta field v (fb2Meta s)}
79+ deleteMeta field s = s {fb2Meta = deleteMeta field (fb2Meta s)}
80+
81+readFB2 :: PandocMonad m => ReaderOptions -> Text -> m Pandoc
82+readFB2 _ inp = do
83+ (bs, st) <- runStateT (mapM parseBlock $ parseXML (crFilter inp)) def
84+ let authors = if null $ fb2Authors st
85+ then id
86+ else setMeta "author" (map text $ reverse $ fb2Authors st)
87+ pure $ Pandoc (authors $ fb2Meta st) (toList . mconcat $ bs)
88+
89+-- * Utility functions
90+
91+trim :: String -> String
92+trim = dropWhileEnd isSpace . dropWhile isSpace
93+
94+removeHash :: String -> String
95+removeHash ('#':xs) = xs
96+removeHash xs = xs
97+
98+convertEntity :: String -> String
99+convertEntity e = fromMaybe (map toUpper e) (lookupEntity e)
100+
101+parseInline :: PandocMonad m => Content -> FB2 m Inlines
102+parseInline (Elem e) =
103+ case qName $ elName e of
104+ "strong" -> strong <$> parseStyleType e
105+ "emphasis" -> emph <$> parseStyleType e
106+ "style" -> parseNamedStyle e
107+ "a" -> parseLinkType e
108+ "strikethrough" -> strikeout <$> parseStyleType e
109+ "sub" -> subscript <$> parseStyleType e
110+ "sup" -> superscript <$> parseStyleType e
111+ "code" -> pure $ code $ strContent e
112+ "image" -> parseInlineImageElement e
113+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ ".")
114+parseInline (Text x) = pure $ text $ cdData x
115+parseInline (CRef r) = pure $ str $ convertEntity r
116+
117+parseSubtitle :: PandocMonad m => Element -> FB2 m Blocks
118+parseSubtitle e = headerWith ("", ["unnumbered"], []) <$> gets fb2SectionLevel <*> parsePType e
119+
120+-- * Root element parser
121+
122+parseBlock :: PandocMonad m => Content -> FB2 m Blocks
123+parseBlock (Elem e) =
124+ case qName $ elName e of
125+ "?xml" -> pure mempty
126+ "FictionBook" -> mconcat <$> mapM parseFictionBookChild (elChildren e)
127+ name -> report (UnexpectedXmlElement name "root") $> mempty
128+parseBlock _ = pure mempty
129+
130+-- | Parse a child of @\<FictionBook>@ element.
131+parseFictionBookChild :: PandocMonad m => Element -> FB2 m Blocks
132+parseFictionBookChild e =
133+ case qName $ elName e of
134+ "stylesheet" -> pure mempty -- stylesheet is ignored
135+ "description" -> mempty <$ mapM_ parseDescriptionChild (elChildren e)
136+ "body" -> mconcat <$> mapM parseBodyChild (elChildren e)
137+ "binary" -> mempty <$ parseBinaryElement e
138+ name -> report (UnexpectedXmlElement name "FictionBook") $> mempty
139+
140+-- | Parse a child of @\<description>@ element.
141+parseDescriptionChild :: PandocMonad m => Element -> FB2 m ()
142+parseDescriptionChild e =
143+ case qName $ elName e of
144+ "title-info" -> mapM_ parseTitleInfoChild (elChildren e)
145+ "src-title-info" -> pure () -- ignore
146+ "document-info" -> pure ()
147+ "publish-info" -> pure ()
148+ "custom-info" -> pure ()
149+ "output" -> pure ()
150+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ "in description.")
151+
152+-- | Parse a child of @\<body>@ element.
153+parseBodyChild :: PandocMonad m => Element -> FB2 m Blocks
154+parseBodyChild e =
155+ case qName $ elName e of
156+ "image" -> parseImageElement e
157+ "title" -> header <$> gets fb2SectionLevel <*> parseTitleType (elContent e)
158+ "epigraph" -> parseEpigraph e
159+ "section" -> parseSection e
160+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in body.")
161+
162+-- | Parse a @\<binary>@ element.
163+parseBinaryElement :: PandocMonad m => Element -> FB2 m ()
164+parseBinaryElement e =
165+ case (findAttr (QName "id" Nothing Nothing) e, findAttr (QName "content-type" Nothing Nothing) e) of
166+ (Nothing, _) -> throwError $ PandocParseError "<binary> element must have an \"id\" attribute"
167+ (Just _, Nothing) -> throwError $ PandocParseError "<binary> element must have a \"content-type\" attribute"
168+ (Just filename, contentType) -> insertMedia filename contentType (decodeLenient (pack (strContent e)))
169+
170+-- * Type parsers
171+
172+-- | Parse @authorType@
173+parseAuthor :: PandocMonad m => Element -> FB2 m String
174+parseAuthor e = unwords <$> mapM parseAuthorChild (elChildren e)
175+
176+parseAuthorChild :: PandocMonad m => Element -> FB2 m String
177+parseAuthorChild e =
178+ case qName $ elName e of
179+ "first-name" -> pure $ strContent e
180+ "middle-name" -> pure $ strContent e
181+ "last-name" -> pure $ strContent e
182+ "nickname" -> pure $ strContent e
183+ "home-page" -> pure $ strContent e
184+ "email" -> pure $ strContent e
185+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in author.")
186+
187+-- | Parse @titleType@
188+parseTitle :: PandocMonad m => Element -> FB2 m Blocks
189+parseTitle e = header <$> gets fb2SectionLevel <*> parseTitleType (elContent e)
190+
191+parseTitleType :: PandocMonad m => [Content] -> FB2 m Inlines
192+parseTitleType c = mconcat . intersperse linebreak . catMaybes <$> mapM parseTitleContent c
193+
194+parseTitleContent :: PandocMonad m => Content -> FB2 m (Maybe Inlines)
195+parseTitleContent (Elem e) =
196+ case qName $ elName e of
197+ "p" -> Just <$> parsePType e
198+ "empty-line" -> pure $ Just mempty
199+ _ -> pure mempty
200+parseTitleContent _ = pure Nothing
201+
202+-- | Parse @imageType@
203+parseImageElement :: PandocMonad m => Element -> FB2 m Blocks
204+parseImageElement e =
205+ case href of
206+ Just src -> pure $ para $ imageWith (imgId, [], []) (removeHash src) title alt
207+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: image without href."
208+ where alt = maybe mempty str $ findAttr (QName "alt" Nothing Nothing) e
209+ title = fromMaybe "" $ findAttr (QName "title" Nothing Nothing) e
210+ imgId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) e
211+ href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
212+
213+-- | Parse @pType@
214+parsePType :: PandocMonad m => Element -> FB2 m Inlines
215+parsePType = parseStyleType -- TODO add support for optional "id" and "style" attributes
216+
217+-- | Parse @citeType@
218+parseCite :: PandocMonad m => Element -> FB2 m Blocks
219+parseCite e = blockQuote . mconcat <$> mapM parseCiteChild (elChildren e)
220+
221+-- | Parse @citeType@ child
222+parseCiteChild :: PandocMonad m => Element -> FB2 m Blocks
223+parseCiteChild e =
224+ case qName $ elName e of
225+ "p" -> para <$> parsePType e
226+ "poem" -> parsePoem e
227+ "empty-line" -> pure horizontalRule
228+ "subtitle" -> parseSubtitle e
229+ "table" -> parseTable e
230+ "text-author" -> para <$> parsePType e
231+ name -> report (UnexpectedXmlElement name "cite") $> mempty
232+
233+-- | Parse @poemType@
234+parsePoem :: PandocMonad m => Element -> FB2 m Blocks
235+parsePoem e = mconcat <$> mapM parsePoemChild (elChildren e)
236+
237+parsePoemChild :: PandocMonad m => Element -> FB2 m Blocks
238+parsePoemChild e =
239+ case qName $ elName e of
240+ "title" -> parseTitle e
241+ "subtitle" -> parseSubtitle e
242+ "epigraph" -> parseEpigraph e
243+ "stanza" -> parseStanza e
244+ "text-author" -> para <$> parsePType e
245+ "date" -> pure $ para $ text $ strContent e
246+ name -> report (UnexpectedXmlElement name "poem") $> mempty
247+
248+parseStanza :: PandocMonad m => Element -> FB2 m Blocks
249+parseStanza e = fromList . joinLineBlocks . toList . mconcat <$> mapM parseStanzaChild (elChildren e)
250+
251+joinLineBlocks :: [Block] -> [Block]
252+joinLineBlocks (LineBlock xs:LineBlock ys:zs) = joinLineBlocks (LineBlock (xs ++ ys) : zs)
253+joinLineBlocks (x:xs) = x:joinLineBlocks xs
254+joinLineBlocks [] = []
255+
256+parseStanzaChild :: PandocMonad m => Element -> FB2 m Blocks
257+parseStanzaChild e =
258+ case qName $ elName e of
259+ "title" -> parseTitle e
260+ "subtitle" -> parseSubtitle e
261+ "v" -> lineBlock . (:[]) <$> parsePType e
262+ name -> report (UnexpectedXmlElement name "stanza") $> mempty
263+
264+-- | Parse @epigraphType@
265+parseEpigraph :: PandocMonad m => Element -> FB2 m Blocks
266+parseEpigraph e =
267+ divWith (divId, ["epigraph"], []) . mconcat <$> mapM parseEpigraphChild (elChildren e)
268+ where divId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) e
269+
270+parseEpigraphChild :: PandocMonad m => Element -> FB2 m Blocks
271+parseEpigraphChild e =
272+ case qName $ elName e of
273+ "p" -> para <$> parsePType e
274+ "poem" -> parsePoem e
275+ "cite" -> parseCite e
276+ "empty-line" -> pure horizontalRule
277+ "text-author" -> para <$> parsePType e
278+ name -> report (UnexpectedXmlElement name "epigraph") $> mempty
279+
280+-- | Parse @annotationType@
281+parseAnnotation :: PandocMonad m => Element -> FB2 m Blocks
282+parseAnnotation e = mconcat <$> mapM parseAnnotationChild (elChildren e)
283+
284+parseAnnotationChild :: PandocMonad m => Element -> FB2 m Blocks
285+parseAnnotationChild e =
286+ case qName $ elName e of
287+ "p" -> para <$> parsePType e
288+ "poem" -> parsePoem e
289+ "cite" -> parseCite e
290+ "subtitle" -> parseSubtitle e
291+ "table" -> parseTable e
292+ "empty-line" -> pure horizontalRule
293+ name -> report (UnexpectedXmlElement name "annotation") $> mempty
294+
295+-- | Parse @sectionType@
296+parseSection :: PandocMonad m => Element -> FB2 m Blocks
297+parseSection e = do
298+ n <- gets fb2SectionLevel
299+ modify $ \st -> st{ fb2SectionLevel = n + 1 }
300+ let sectionId = fromMaybe "" $ findAttr (QName "id" Nothing Nothing) e
301+ bs <- divWith (sectionId, ["section"], []) . mconcat <$> mapM parseSectionChild (elChildren e)
302+ modify $ \st -> st{ fb2SectionLevel = n }
303+ pure bs
304+
305+parseSectionChild :: PandocMonad m => Element -> FB2 m Blocks
306+parseSectionChild e =
307+ case qName $ elName e of
308+ "title" -> parseBodyChild e
309+ "epigraph" -> parseEpigraph e
310+ "image" -> parseImageElement e
311+ "annotation" -> parseAnnotation e
312+ "poem" -> parsePoem e
313+ "cite" -> parseCite e
314+ "empty-line" -> pure horizontalRule
315+ "table" -> parseTable e
316+ "subtitle" -> parseSubtitle e
317+ "p" -> para <$> parsePType e
318+ "section" -> parseSection e
319+ name -> report (UnexpectedXmlElement name "section") $> mempty
320+
321+-- | parse @styleType@
322+parseStyleType :: PandocMonad m => Element -> FB2 m Inlines
323+parseStyleType e = mconcat <$> mapM parseInline (elContent e)
324+
325+-- | Parse @namedStyleType@
326+parseNamedStyle :: PandocMonad m => Element -> FB2 m Inlines
327+parseNamedStyle e = do
328+ content <- mconcat <$> mapM parseNamedStyleChild (elContent e)
329+ let lang = maybeToList $ ("lang",) <$> findAttr (QName "lang" Nothing (Just "xml")) e
330+ case findAttr (QName "name" Nothing Nothing) e of
331+ Just name -> pure $ spanWith ("", [name], lang) content
332+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: link without required name."
333+
334+parseNamedStyleChild :: PandocMonad m => Content -> FB2 m Inlines
335+parseNamedStyleChild (Elem e) =
336+ case qName (elName e) of
337+ "strong" -> strong <$> parseStyleType e
338+ "emphasis" -> emph <$> parseStyleType e
339+ "style" -> parseNamedStyle e
340+ "a" -> parseLinkType e
341+ "strikethrough" -> strikeout <$> parseStyleType e
342+ "sub" -> subscript <$> parseStyleType e
343+ "sup" -> superscript <$> parseStyleType e
344+ "code" -> pure $ code $ strContent e
345+ "image" -> parseInlineImageElement e
346+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ ".")
347+parseNamedStyleChild x = parseInline x
348+
349+-- | Parse @linkType@
350+parseLinkType :: PandocMonad m => Element -> FB2 m Inlines
351+parseLinkType e = do
352+ content <- mconcat <$> mapM parseStyleLinkType (elContent e)
353+ case findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e of
354+ Just href -> pure $ link href "" content
355+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: link without required href."
356+
357+-- | Parse @styleLinkType@
358+parseStyleLinkType :: PandocMonad m => Content -> FB2 m Inlines
359+parseStyleLinkType x@(Elem e) =
360+ case qName (elName e) of
361+ "a" -> throwError $ PandocParseError "Couldn't parse FB2 file: links cannot be nested."
362+ _ -> parseInline x
363+parseStyleLinkType x = parseInline x
364+
365+-- | Parse @tableType@
366+parseTable :: PandocMonad m => Element -> FB2 m Blocks
367+parseTable _ = pure mempty -- TODO: tables are not supported yet
368+
369+-- | Parse @title-infoType@
370+parseTitleInfoChild :: PandocMonad m => Element -> FB2 m ()
371+parseTitleInfoChild e =
372+ case qName (elName e) of
373+ "genre" -> pure ()
374+ "author" -> parseAuthor e >>= \author -> modify (\st -> st {fb2Authors = author:fb2Authors st})
375+ "book-title" -> modify (setMeta "title" (text $ strContent e))
376+ "annotation" -> parseAnnotation e >>= modify . setMeta "abstract"
377+ "keywords" -> modify (setMeta "keywords" (map (MetaString . trim) $ splitOn "," $ strContent e))
378+ "date" -> modify (setMeta "date" (text $ strContent e))
379+ "coverpage" -> parseCoverPage e
380+ "lang" -> pure ()
381+ "src-lang" -> pure ()
382+ "translator" -> pure ()
383+ "sequence" -> pure ()
384+ name -> throwError $ PandocParseError ("Couldn't parse FB2 file: unexpected element " ++ name ++ " in title-info.")
385+
386+parseCoverPage :: PandocMonad m => Element -> FB2 m ()
387+parseCoverPage e =
388+ case findChild (QName "image" (Just "http://www.gribuser.ru/xml/fictionbook/2.0") Nothing) e of
389+ Just img -> case href of
390+ Just src -> modify (setMeta "cover-image" (MetaString $ removeHash src))
391+ Nothing -> pure ()
392+ where href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) img
393+ Nothing -> pure ()
394+
395+-- | Parse @inlineImageType@ element
396+parseInlineImageElement :: PandocMonad m
397+ => Element
398+ -> FB2 m Inlines
399+parseInlineImageElement e =
400+ case href of
401+ Just src -> pure $ imageWith ("", [], []) (removeHash src) "" alt
402+ Nothing -> throwError $ PandocParseError "Couldn't parse FB2 file: inline image without href."
403+ where alt = maybe mempty str $ findAttr (QName "alt" Nothing Nothing) e
404+ href = findAttr (QName "href" (Just "http://www.w3.org/1999/xlink") Nothing) e
src/Text/Pandoc/Readers/HTML.hs+7−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE FlexibleInstances #-}
34{-# LANGUAGE MultiParamTypeClasses #-}
@@ -42,6 +43,7 @@ module Text.Pandoc.Readers.HTML ( readHtml
4243 , isCommentTag
4344 ) where
4445
46+import Prelude
4547import Control.Applicative ((<|>))
4648import Control.Arrow (first)
4749import Control.Monad (guard, mplus, msum, mzero, unless, void)
@@ -54,7 +56,7 @@ import Data.List (isPrefixOf)
5456import Data.List.Split (wordsBy, splitWhen)
5557import qualified Data.Map as M
5658import Data.Maybe (fromMaybe, isJust, isNothing)
57−import Data.Monoid (First (..), (<>))
59+import Data.Monoid (First (..))
5860import qualified Data.Set as Set
5961import Data.Text (Text)
6062import qualified Data.Text as T
@@ -508,14 +510,16 @@ pTable = try $ do
508510 [Plain _] -> True
509511 _ -> False
510512 let isSimple = all isSinglePlain $ concat (head':rows''')
511− let cols = length $ if null head' then head rows''' else head'
513+ let cols = if null head'
514+ then maximum (map length rows''')
515+ else length head'
512516 -- add empty cells to short rows
513517 let addEmpties r = case cols - length r of
514518 n | n > 0 -> r <> replicate n mempty
515519 | otherwise -> r
516520 let rows = map addEmpties rows'''
517521 let aligns = case rows'' of
518− (cs:_) -> map fst cs
522+ (cs:_) -> take cols $ map fst cs ++ repeat AlignDefault
519523 _ -> replicate cols AlignDefault
520524 let widths = if null widths'
521525 then if isSimple
src/Text/Pandoc/Readers/Haddock.hs+20−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{- |
34 Module : Text.Pandoc.Readers.Haddock
@@ -14,13 +15,13 @@ module Text.Pandoc.Readers.Haddock
1415 ( readHaddock
1516 ) where
1617
18+import Prelude
1719import Control.Monad.Except (throwError)
1820import Data.List (intersperse, stripPrefix)
1921import Data.Maybe (fromMaybe)
20−import Data.Monoid ((<>))
2122import Data.Text (Text, unpack)
2223import Documentation.Haddock.Parser
23−import Documentation.Haddock.Types
24+import Documentation.Haddock.Types as H
2425import Text.Pandoc.Builder (Blocks, Inlines)
2526import qualified Text.Pandoc.Builder as B
2627import Text.Pandoc.Class (PandocMonad)
@@ -86,6 +87,20 @@ docHToBlocks d' =
8687 DocProperty s -> B.codeBlockWith ("",["property","haskell"],[]) (trim s)
8788 DocExamples es -> mconcat $ map (\e ->
8889 makeExample ">>>" (exampleExpression e) (exampleResult e)) es
90+#if MIN_VERSION_haddock_library(1,5,0)
91+ DocTable H.Table{ tableHeaderRows = headerRows
92+ , tableBodyRows = bodyRows
93+ }
94+ -> let toCells = map (docHToBlocks . tableCellContents) . tableRowCells
95+ (header, body) =
96+ if null headerRows
97+ then ([], map toCells bodyRows)
98+ else (toCells (head headerRows),
99+ map toCells (tail headerRows ++ bodyRows))
100+ colspecs = replicate (maximum (map length body))
101+ (AlignDefault, 0.0)
102+ in B.table mempty colspecs header body
103+#endif
89104
90105 where inlineFallback = B.plain $ docHToInlines False d'
91106 consolidatePlains = B.fromList . consolidatePlains' . B.toList
@@ -134,6 +149,9 @@ docHToInlines isCode d' =
134149 DocAName s -> B.spanWith (s,["anchor"],[]) mempty
135150 DocProperty _ -> mempty
136151 DocExamples _ -> mempty
152+#if MIN_VERSION_haddock_library(1,5,0)
153+ DocTable _ -> mempty
154+#endif
137155
138156-- | Create an 'Example', stripping superfluous characters as appropriate
139157makeExample :: String -> String -> [String] -> Blocks
src/Text/Pandoc/Readers/JATS.hs+33−1
@@ -1,5 +1,37 @@
1−{-# LANGUAGE ExplicitForAll, TupleSections #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE TupleSections #-}
3+{-
4+Copyright (C) 2017-2018 Hamish Mackenzie
5+
6+This program is free software; you can redistribute it and/or modify
7+it under the terms of the GNU General Public License as published by
8+the Free Software Foundation; either version 2 of the License, or
9+(at your option) any later version.
10+
11+This program is distributed in the hope that it will be useful,
12+but WITHOUT ANY WARRANTY; without even the implied warranty of
13+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+GNU General Public License for more details.
15+
16+You should have received a copy of the GNU General Public License
17+along with this program; if not, write to the Free Software
18+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19+-}
20+
21+{- |
22+ Module : Text.Pandoc.Readers.JATS
23+ Copyright : Copyright (C) 2017-2018 Hamish Mackenzie
24+ License : GNU GPL, version 2 or above
25+
26+ Maintainer : John MacFarlane <jgm@berkeley.edu>
27+ Stability : alpha
28+ Portability : portable
29+
30+Conversion of JATS XML to 'Pandoc' document.
31+-}
32+
233module Text.Pandoc.Readers.JATS ( readJATS ) where
34+import Prelude
335import Control.Monad.State.Strict
436import Data.Char (isDigit, isSpace, toUpper)
537import Data.Default
src/Text/Pandoc/Readers/LaTeX.hs+102−44
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE MultiParamTypeClasses #-}
34{-# LANGUAGE OverloadedStrings #-}
@@ -42,11 +43,12 @@ module Text.Pandoc.Readers.LaTeX ( readLaTeX,
4243 untokenize
4344 ) where
4445
46+import Prelude
4547import Control.Applicative (many, optional, (<|>))
4648import Control.Monad
4749import Control.Monad.Except (throwError)
4850import Control.Monad.Trans (lift)
49−import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower)
51+import Data.Char (chr, isAlphaNum, isDigit, isLetter, ord, toLower, toUpper)
5052import Data.Default
5153import Data.List (intercalate, isPrefixOf)
5254import qualified Data.Map as M
@@ -60,7 +62,7 @@ import Text.Pandoc.BCP47 (Lang (..), renderLang)
6062import Text.Pandoc.Builder
6163import Text.Pandoc.Class (PandocMonad, PandocPure, getResourcePath, lookupEnv,
6264 readFileFromDirs, report, setResourcePath,
63− setTranslations, translateTerm)
65+ setTranslations, translateTerm, trace)
6466import Text.Pandoc.Error (PandocError (PandocMacroLoop, PandocParseError, PandocParsecError))
6567import Text.Pandoc.Highlighting (fromListingsLanguage, languagesByExtension)
6668import Text.Pandoc.ImageSize (numUnit, showFl)
@@ -74,6 +76,7 @@ import Text.Pandoc.Shared
7476import qualified Text.Pandoc.Translations as Translations
7577import Text.Pandoc.Walk
7678import Text.Parsec.Pos
79+import qualified Text.Pandoc.Builder as B
7780
7881-- for debugging:
7982-- import Text.Pandoc.Extensions (getDefaultExtensions)
@@ -161,6 +164,7 @@ data LaTeXState = LaTeXState{ sOptions :: ReaderOptions
161164 , sInTableCell :: Bool
162165 , sLastHeaderNum :: HeaderNum
163166 , sLabels :: M.Map String [Inline]
167+ , sHasChapters :: Bool
164168 , sToggles :: M.Map String Bool
165169 }
166170 deriving Show
@@ -180,6 +184,7 @@ defaultLaTeXState = LaTeXState{ sOptions = def
180184 , sInTableCell = False
181185 , sLastHeaderNum = HeaderNum []
182186 , sLabels = M.empty
187+ , sHasChapters = False
183188 , sToggles = M.empty
184189 }
185190
@@ -237,21 +242,30 @@ withVerbatimMode parser = do
237242 return result
238243
239244rawLaTeXParser :: (PandocMonad m, HasMacros s, HasReaderOptions s)
240− => LP m a -> ParserT String s m (a, String)
241−rawLaTeXParser parser = do
245+ => LP m a -> LP m a -> ParserT String s m (a, String)
246+rawLaTeXParser parser valParser = do
242247 inp <- getInput
243248 let toks = tokenize "source" $ T.pack inp
244249 pstate <- getState
245− let lstate = def{ sOptions = extractReaderOptions pstate
246− , sMacros = extractMacros pstate }
247− let rawparser = (,) <$> withRaw parser <*> getState
248− res <- lift $ runParserT rawparser lstate "chunk" toks
249− case res of
250+ let lstate = def{ sOptions = extractReaderOptions pstate }
251+ let lstate' = lstate { sMacros = extractMacros pstate }
252+ let rawparser = (,) <$> withRaw valParser <*> getState
253+ res' <- lift $ runParserT (snd <$> withRaw parser) lstate "chunk" toks
254+ case res' of
250255 Left _ -> mzero
251− Right ((val, raw), st) -> do
252− updateState (updateMacros (sMacros st <>))
253− rawstring <- takeP (T.length (untokenize raw))
254− return (val, rawstring)
256+ Right toks' -> do
257+ res <- lift $ runParserT (do doMacros 0
258+ -- retokenize, applying macros
259+ ts <- many (satisfyTok (const True))
260+ setInput ts
261+ rawparser)
262+ lstate' "chunk" toks'
263+ case res of
264+ Left _ -> mzero
265+ Right ((val, raw), st) -> do
266+ updateState (updateMacros (sMacros st <>))
267+ _ <- takeP (T.length (untokenize toks'))
268+ return (val, T.unpack (untokenize raw))
255269
256270applyMacros :: (PandocMonad m, HasMacros s, HasReaderOptions s)
257271 => String -> ParserT String s m String
@@ -272,19 +286,18 @@ rawLaTeXBlock = do
272286 lookAhead (try (char '\\' >> letter))
273287 -- we don't want to apply newly defined latex macros to their own
274288 -- definitions:
275− snd <$> rawLaTeXParser macroDef
276− <|> ((snd <$> rawLaTeXParser (environment <|> blockCommand)) >>= applyMacros)
289+ snd <$> rawLaTeXParser (environment <|> macroDef <|> blockCommand) blocks
277290
278291rawLaTeXInline :: (PandocMonad m, HasMacros s, HasReaderOptions s)
279292 => ParserT String s m String
280293rawLaTeXInline = do
281294 lookAhead (try (char '\\' >> letter))
282− rawLaTeXParser (inlineEnvironment <|> inlineCommand') >>= applyMacros . snd
295+ snd <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines
283296
284297inlineCommand :: PandocMonad m => ParserT String ParserState m Inlines
285298inlineCommand = do
286299 lookAhead (try (char '\\' >> letter))
287− fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand')
300+ fst <$> rawLaTeXParser (inlineEnvironment <|> inlineCommand') inlines
288301
289302tokenize :: SourceName -> Text -> [Tok]
290303tokenize sourcename = totoks (initialPos sourcename)
@@ -665,7 +678,7 @@ dosiunitx = do
665678 skipopts
666679 value <- tok
667680 valueprefix <- option "" $ bracketed tok
668− unit <- tok
681+ unit <- inlineCommand' <|> tok
669682 let emptyOr160 "" = ""
670683 emptyOr160 _ = "\160"
671684 return . mconcat $ [valueprefix,
@@ -674,6 +687,12 @@ dosiunitx = do
674687 emptyOr160 unit,
675688 unit]
676689
690+-- siunitx's \square command
691+dosquare :: PandocMonad m => LP m Inlines
692+dosquare = do
693+ unit <- inlineCommand' <|> tok
694+ return . mconcat $ [unit, "\178"]
695+
677696lit :: String -> LP m Inlines
678697lit = pure . str
679698
@@ -1034,13 +1053,28 @@ dollarsMath :: PandocMonad m => LP m Inlines
10341053dollarsMath = do
10351054 symbol '$'
10361055 display <- option False (True <$ symbol '$')
1037− contents <- trim . toksToString <$>
1038− many (notFollowedBy (symbol '$') >> anyTok)
1039− if display
1040− then
1041− mathDisplay contents <$ try (symbol '$' >> symbol '$')
1042− <|> (guard (null contents) >> return (mathInline ""))
1043− else mathInline contents <$ symbol '$'
1056+ (do contents <- try $ T.unpack <$> pDollarsMath 0
1057+ if display
1058+ then (mathDisplay contents <$ symbol '$')
1059+ else return $ mathInline contents)
1060+ <|> (guard display >> return (mathInline ""))
1061+
1062+-- Int is number of embedded groupings
1063+pDollarsMath :: PandocMonad m => Int -> LP m Text
1064+pDollarsMath n = do
1065+ Tok _ toktype t <- anyTok
1066+ case toktype of
1067+ Symbol | t == "$"
1068+ , n == 0 -> return mempty
1069+ | t == "\\" -> do
1070+ Tok _ _ t' <- anyTok
1071+ return (t <> t')
1072+ | t == "{" -> (t <>) <$> pDollarsMath (n+1)
1073+ | t == "}" ->
1074+ if n > 0
1075+ then (t <>) <$> pDollarsMath (n-1)
1076+ else mzero
1077+ _ -> (t <>) <$> pDollarsMath n
10441078
10451079-- citations
10461080
@@ -1161,7 +1195,7 @@ singleChar = try $ do
11611195 else return $ Tok pos toktype t
11621196
11631197opt :: PandocMonad m => LP m Inlines
1164−opt = bracketed inline
1198+opt = bracketed inline <|> (str . T.unpack <$> rawopt)
11651199
11661200rawopt :: PandocMonad m => LP m Text
11671201rawopt = do
@@ -1304,6 +1338,12 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
13041338 , ("slshape", extractSpaces emph <$> inlines)
13051339 , ("scshape", extractSpaces smallcaps <$> inlines)
13061340 , ("bfseries", extractSpaces strong <$> inlines)
1341+ , ("MakeUppercase", makeUppercase <$> tok)
1342+ , ("MakeTextUppercase", makeUppercase <$> tok) -- textcase
1343+ , ("uppercase", makeUppercase <$> tok)
1344+ , ("MakeLowercase", makeLowercase <$> tok)
1345+ , ("MakeTextLowercase", makeLowercase <$> tok)
1346+ , ("lowercase", makeLowercase <$> tok)
13071347 , ("/", pure mempty) -- italic correction
13081348 , ("aa", lit "å")
13091349 , ("AA", lit "Å")
@@ -1467,6 +1507,13 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
14671507 , ("acsp", doAcronymPlural "abbrv")
14681508 -- siuntix
14691509 , ("SI", dosiunitx)
1510+ -- units of siuntix
1511+ , ("celsius", lit "°C")
1512+ , ("degreeCelsius", lit "°C")
1513+ , ("gram", lit "g")
1514+ , ("meter", lit "m")
1515+ , ("milli", lit "m")
1516+ , ("square", dosquare)
14701517 -- hyphenat
14711518 , ("bshyp", lit "\\\173")
14721519 , ("fshyp", lit "/\173")
@@ -1497,6 +1544,16 @@ inlineCommands = M.union inlineLanguageCommands $ M.fromList
14971544 , ("foreignlanguage", foreignlanguage)
14981545 ]
14991546
1547+makeUppercase :: Inlines -> Inlines
1548+makeUppercase = fromList . walk (alterStr (map toUpper)) . toList
1549+
1550+makeLowercase :: Inlines -> Inlines
1551+makeLowercase = fromList . walk (alterStr (map toLower)) . toList
1552+
1553+alterStr :: (String -> String) -> Inline -> Inline
1554+alterStr f (Str xs) = Str (f xs)
1555+alterStr _ x = x
1556+
15001557foreignlanguage :: PandocMonad m => LP m Inlines
15011558foreignlanguage = do
15021559 babelLang <- T.unpack . untokenize <$> braced
@@ -1669,6 +1726,9 @@ treatAsBlock = Set.fromList
16691726 , "clearpage"
16701727 , "pagebreak"
16711728 , "titleformat"
1729+ , "listoffigures"
1730+ , "listoftables"
1731+ , "write"
16721732 ]
16731733
16741734isInlineCommand :: Text -> Bool
@@ -1968,9 +2028,13 @@ section starred (ident, classes, kvs) lvl = do
19682028 try (spaces >> controlSeq "label"
19692029 >> spaces >> toksToString <$> braced)
19702030 let classes' = if starred then "unnumbered" : classes else classes
2031+ when (lvl == 0) $
2032+ updateState $ \st -> st{ sHasChapters = True }
19712033 unless starred $ do
19722034 hn <- sLastHeaderNum <$> getState
1973− let num = incrementHeaderNum lvl hn
2035+ hasChapters <- sHasChapters <$> getState
2036+ let lvl' = lvl + if hasChapters then 1 else 0
2037+ let num = incrementHeaderNum lvl' hn
19742038 updateState $ \st -> st{ sLastHeaderNum = num }
19752039 updateState $ \st -> st{ sLabels = M.insert lab
19762040 [Str (renderHeaderNum num)]
@@ -2095,6 +2159,7 @@ environments :: PandocMonad m => M.Map Text (LP m Blocks)
20952159environments = M.fromList
20962160 [ ("document", env "document" blocks)
20972161 , ("abstract", mempty <$ (env "abstract" blocks >>= addMeta "abstract"))
2162+ , ("sloppypar", env "sloppypar" $ blocks)
20982163 , ("letter", env "letter" letterContents)
20992164 , ("minipage", env "minipage" $
21002165 skipopts *> spaces *> optional braced *> spaces *> blocks)
@@ -2126,19 +2191,6 @@ environments = M.fromList
21262191 codeBlockWith attr <$> verbEnv "lstlisting")
21272192 , ("minted", minted)
21282193 , ("obeylines", obeylines)
2129− , ("displaymath", mathEnvWith para Nothing "displaymath")
2130− , ("equation", mathEnvWith para Nothing "equation")
2131− , ("equation*", mathEnvWith para Nothing "equation*")
2132− , ("gather", mathEnvWith para (Just "gathered") "gather")
2133− , ("gather*", mathEnvWith para (Just "gathered") "gather*")
2134− , ("multline", mathEnvWith para (Just "gathered") "multline")
2135− , ("multline*", mathEnvWith para (Just "gathered") "multline*")
2136− , ("eqnarray", mathEnvWith para (Just "aligned") "eqnarray")
2137− , ("eqnarray*", mathEnvWith para (Just "aligned") "eqnarray*")
2138− , ("align", mathEnvWith para (Just "aligned") "align")
2139− , ("align*", mathEnvWith para (Just "aligned") "align*")
2140− , ("alignat", mathEnvWith para (Just "aligned") "alignat")
2141− , ("alignat*", mathEnvWith para (Just "aligned") "alignat*")
21422194 , ("tikzpicture", rawVerbEnv "tikzpicture")
21432195 -- etoolbox
21442196 , ("ifstrequal", ifstrequal)
@@ -2149,11 +2201,14 @@ environments = M.fromList
21492201 ]
21502202
21512203environment :: PandocMonad m => LP m Blocks
2152−environment = do
2204+environment = try $ do
21532205 controlSeq "begin"
21542206 name <- untokenize <$> braced
2155− M.findWithDefault mzero name environments
2156− <|> rawEnv name
2207+ M.findWithDefault mzero name environments <|>
2208+ if M.member name (inlineEnvironments
2209+ :: M.Map Text (LP PandocPure Inlines))
2210+ then mzero
2211+ else rawEnv name
21572212
21582213env :: PandocMonad m => Text -> LP m a -> LP m a
21592214env name p = p <* end_ name
@@ -2532,13 +2587,16 @@ addTableCaption = walkM go
25322587
25332588
25342589block :: PandocMonad m => LP m Blocks
2535−block = (mempty <$ spaces1)
2590+block = do
2591+ res <- (mempty <$ spaces1)
25362592 <|> environment
25372593 <|> include
25382594 <|> macroDef
25392595 <|> blockCommand
25402596 <|> paragraph
25412597 <|> grouped block
2598+ trace (take 60 $ show $ B.toList res)
2599+ return res
25422600
25432601blocks :: PandocMonad m => LP m Blocks
25442602blocks = mconcat <$> many block
src/Text/Pandoc/Readers/LaTeX/Types.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2017-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -34,6 +35,7 @@ module Text.Pandoc.Readers.LaTeX.Types ( Tok(..)
3435 , SourcePos
3536 )
3637where
38+import Prelude
3739import Data.Text (Text)
3840import Text.Parsec.Pos (SourcePos)
3941
src/Text/Pandoc/Readers/Markdown.hs+30−12
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE RelaxedPolyRec #-}
23{-# LANGUAGE ScopedTypeVariables #-}
34
@@ -32,6 +33,7 @@ Conversion of markdown-formatted plain text to 'Pandoc' document.
3233-}
3334module Text.Pandoc.Readers.Markdown ( readMarkdown ) where
3435
36+import Prelude
3537import Control.Monad
3638import Control.Monad.Except (throwError)
3739import Data.Char (isAlphaNum, isPunctuation, isSpace, toLower)
@@ -39,7 +41,6 @@ import qualified Data.HashMap.Strict as H
3941import Data.List (intercalate, sortBy, transpose, elemIndex)
4042import qualified Data.Map as M
4143import Data.Maybe
42−import Data.Monoid ((<>))
4344import Data.Ord (comparing)
4445import Data.Scientific (base10Exponent, coefficient)
4546import qualified Data.Set as Set
@@ -162,7 +163,7 @@ inlinesInBalancedBrackets =
162163 stripBracket xs = if last xs == ']' then init xs else xs
163164 go :: PandocMonad m => Int -> MarkdownParser m ()
164165 go 0 = return ()
165− go openBrackets =
166+ go openBrackets =
166167 (() <$ (escapedChar <|>
167168 code <|>
168169 rawHtmlInline <|>
@@ -673,6 +674,8 @@ keyValAttr = try $ do
673674 char '='
674675 val <- enclosed (char '"') (char '"') litChar
675676 <|> enclosed (char '\'') (char '\'') litChar
677+ <|> ("" <$ try (string "\"\""))
678+ <|> ("" <$ try (string "''"))
676679 <|> many (escapedChar' <|> noneOf " \t\n\r}")
677680 return $ \(id',cs,kvs) ->
678681 case key of
@@ -909,6 +912,17 @@ listContinuation continuationIndent = try $ do
909912 blanks <- many blankline
910913 return $ concat (x:xs) ++ blanks
911914
915+-- Variant of blanklines that doesn't require blank lines
916+-- before a fence or eof.
917+blanklines' :: PandocMonad m => MarkdownParser m [Char]
918+blanklines' = blanklines <|> try checkDivCloser
919+ where checkDivCloser = do
920+ guardEnabled Ext_fenced_divs
921+ divLevel <- stateFencedDivLevel <$> getState
922+ guard (divLevel >= 1)
923+ lookAhead divFenceEnd
924+ return ""
925+
912926notFollowedByDivCloser :: PandocMonad m => MarkdownParser m ()
913927notFollowedByDivCloser =
914928 guardDisabled Ext_fenced_divs <|>
@@ -1250,7 +1264,7 @@ alignType strLst len =
12501264
12511265-- Parse a table footer - dashed lines followed by blank line.
12521266tableFooter :: PandocMonad m => MarkdownParser m String
1253−tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines
1267+tableFooter = try $ skipNonindentSpaces >> many1 (dashedLine '-') >> blanklines'
12541268
12551269-- Parse a table separator - dashed line.
12561270tableSep :: PandocMonad m => MarkdownParser m Char
@@ -1261,7 +1275,7 @@ rawTableLine :: PandocMonad m
12611275 => [Int]
12621276 -> MarkdownParser m [String]
12631277rawTableLine indices = do
1264− notFollowedBy' (blanklines <|> tableFooter)
1278+ notFollowedBy' (blanklines' <|> tableFooter)
12651279 line <- many1Till anyChar newline
12661280 return $ map trim $ tail $
12671281 splitStringByIndices (init indices) line
@@ -1299,7 +1313,7 @@ simpleTable headless = do
12991313 (aligns, _widths, heads', lines') <-
13001314 tableWith (simpleTableHeader headless) tableLine
13011315 (return ())
1302− (if headless then tableFooter else tableFooter <|> blanklines)
1316+ (if headless then tableFooter else tableFooter <|> blanklines')
13031317 -- Simple tables get 0s for relative column widths (i.e., use default)
13041318 return (aligns, replicate (length aligns) 0, heads', lines')
13051319
@@ -1327,11 +1341,16 @@ multilineTableHeader headless = try $ do
13271341 newline
13281342 let (lengths, lines') = unzip dashes
13291343 let indices = scanl (+) (length initSp) lines'
1344+ -- compensate for the fact that intercolumn spaces are
1345+ -- not included in the last index:
1346+ let indices' = case reverse indices of
1347+ [] -> []
1348+ (x:xs) -> reverse (x+1:xs)
13301349 rawHeadsList <- if headless
13311350 then fmap (map (:[]) . tail .
1332− splitStringByIndices (init indices)) $ lookAhead anyLine
1351+ splitStringByIndices (init indices')) $ lookAhead anyLine
13331352 else return $ transpose $ map
1334− (tail . splitStringByIndices (init indices))
1353+ (tail . splitStringByIndices (init indices'))
13351354 rawContent
13361355 let aligns = zipWith alignType rawHeadsList lengths
13371356 let rawHeads = if headless
@@ -1339,7 +1358,7 @@ multilineTableHeader headless = try $ do
13391358 else map (unlines . map trim) rawHeadsList
13401359 heads <- fmap sequence $
13411360 mapM ((parseFromString' (mconcat <$> many plain)).trim) rawHeads
1342− return (heads, aligns, indices)
1361+ return (heads, aligns, indices')
13431362
13441363-- Parse a grid table: starts with row of '-' on top, then header
13451364-- (which may be grid), then the rows,
@@ -2145,7 +2164,6 @@ singleQuoted = try $ do
21452164doubleQuoted :: PandocMonad m => MarkdownParser m (F Inlines)
21462165doubleQuoted = try $ do
21472166 doubleQuoteStart
2148− contents <- mconcat <$> many (try $ notFollowedBy doubleQuoteEnd >> inline)
2149− withQuoteContext InDoubleQuote (doubleQuoteEnd >> return
2150− (fmap B.doubleQuoted . trimInlinesF $ contents))
2151− <|> return (return (B.str "\8220") <> contents)
2167+ withQuoteContext InDoubleQuote $
2168+ fmap B.doubleQuoted . trimInlinesF . mconcat <$>
2169+ many1Till inline doubleQuoteEnd
src/Text/Pandoc/Readers/MediaWiki.hs+21−9
@@ -1,6 +1,5 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE RelaxedPolyRec #-}
3−{-# LANGUAGE TypeSynonymInstances #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE RelaxedPolyRec #-}
43-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
54{-
65 Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -38,6 +37,7 @@ _ parse templates?
3837-}
3938module Text.Pandoc.Readers.MediaWiki ( readMediaWiki ) where
4039
40+import Prelude
4141import Control.Monad
4242import Control.Monad.Except (throwError)
4343import Data.Char (isDigit, isSpace)
@@ -45,7 +45,6 @@ import qualified Data.Foldable as F
4545import Data.List (intercalate, intersperse, isPrefixOf)
4646import qualified Data.Map as M
4747import Data.Maybe (fromMaybe, maybeToList)
48−import Data.Monoid ((<>))
4948import Data.Sequence (ViewL (..), viewl, (<|))
5049import qualified Data.Set as Set
5150import Data.Text (Text, unpack)
@@ -231,7 +230,8 @@ para = do
231230table :: PandocMonad m => MWParser m Blocks
232231table = do
233232 tableStart
234− styles <- option [] parseAttrs
233+ styles <- option [] $
234+ parseAttrs <* skipMany spaceChar <* optional (char '|')
235235 skipMany spaceChar
236236 optional blanklines
237237 let tableWidth = case lookup "width" styles of
@@ -282,17 +282,29 @@ rowsep = try $ guardColumnOne *> skipSpaces *> sym "|-" <*
282282
283283cellsep :: PandocMonad m => MWParser m ()
284284cellsep = try $ do
285+ col <- sourceColumn <$> getPosition
285286 skipSpaces
286− (char '|' *> notFollowedBy (oneOf "-}+") *> optional (char '|'))
287− <|> (char '!' *> optional (char '!'))
287+ let pipeSep = do
288+ char '|'
289+ notFollowedBy (oneOf "-}+")
290+ if col == 1
291+ then optional (char '|')
292+ else void (char '|')
293+ let exclSep = do
294+ char '!'
295+ if col == 1
296+ then optional (char '!')
297+ else void (char '!')
298+ pipeSep <|> exclSep
288299
289300tableCaption :: PandocMonad m => MWParser m Inlines
290301tableCaption = try $ do
291302 guardColumnOne
292303 skipSpaces
293304 sym "|+"
294− optional (try $ parseAttr *> skipSpaces *> char '|' *> skipSpaces)
295− (trimInlines . mconcat) <$> many (notFollowedBy (cellsep <|> rowsep) *> inline)
305+ optional (try $ parseAttr *> skipSpaces *> char '|' *> blanklines)
306+ (trimInlines . mconcat) <$>
307+ many (notFollowedBy (cellsep <|> rowsep) *> inline)
296308
297309tableRow :: PandocMonad m => MWParser m [((Alignment, Double), Blocks)]
298310tableRow = try $ skipMany htmlComment *> many tableCell
src/Text/Pandoc/Readers/Muse.hs+317−275
@@ -1,4 +1,6 @@
1−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE TupleSections #-}
24{-
35 Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
46
@@ -34,13 +36,14 @@ TODO:
3436- Org tables
3537- table.el tables
3638- Images with attributes (floating and width)
37−- Citations and <biblio>
38−- <play> environment
39+- <cite> tag
3940-}
4041module Text.Pandoc.Readers.Muse (readMuse) where
4142
43+import Prelude
4244import Control.Monad
4345import Control.Monad.Except (throwError)
46+import Data.Bifunctor
4447import Data.Char (isLetter)
4548import Data.Default
4649import Data.List (stripPrefix, intercalate)
@@ -81,24 +84,21 @@ data MuseState = MuseState { museMeta :: F Meta -- ^ Document metadata
8184 , museLastStrPos :: Maybe SourcePos -- ^ Position after last str parsed
8285 , museLogMessages :: [LogMessage]
8386 , museNotes :: M.Map String (SourcePos, F Blocks)
84− , museInLink :: Bool
85− , museInPara :: Bool
87+ , museInLink :: Bool -- ^ True when parsing a link description to avoid nested links
88+ , museInPara :: Bool -- ^ True when looking for a paragraph terminator
8689 }
8790
8891instance Default MuseState where
89− def = defaultMuseState
90−
91−defaultMuseState :: MuseState
92−defaultMuseState = MuseState { museMeta = return nullMeta
93− , museOptions = def
94− , museHeaders = M.empty
95− , museIdentifierList = Set.empty
96− , museLastStrPos = Nothing
97− , museLogMessages = []
98− , museNotes = M.empty
99− , museInLink = False
100− , museInPara = False
101− }
92+ def = MuseState { museMeta = return nullMeta
93+ , museOptions = def
94+ , museHeaders = M.empty
95+ , museIdentifierList = Set.empty
96+ , museLastStrPos = Nothing
97+ , museLogMessages = []
98+ , museNotes = M.empty
99+ , museInLink = False
100+ , museInPara = False
101+ }
102102
103103type MuseParser = ParserT String MuseState
104104
@@ -121,10 +121,7 @@ instance HasLogMessages MuseState where
121121 addLogMessage m s = s{ museLogMessages = m : museLogMessages s }
122122 getLogMessages = reverse . museLogMessages
123123
124−--
125−-- main parser
126−--
127−
124+-- | Parse Muse document
128125parseMuse :: PandocMonad m => MuseParser m Pandoc
129126parseMuse = do
130127 many directive
@@ -136,14 +133,56 @@ parseMuse = do
136133 reportLogMessages
137134 return doc
138135
139−--
140−-- utility functions
141−--
136+-- * Utility functions
137+
138+commonPrefix :: String -> String -> String
139+commonPrefix _ [] = []
140+commonPrefix [] _ = []
141+commonPrefix (x:xs) (y:ys)
142+ | x == y = x : commonPrefix xs ys
143+ | otherwise = []
144+
145+-- | Trim up to one newline from the beginning of the string.
146+lchop :: String -> String
147+lchop s = case s of
148+ '\n':ss -> ss
149+ _ -> s
150+
151+-- | Trim up to one newline from the end of the string.
152+rchop :: String -> String
153+rchop = reverse . lchop . reverse
154+
155+dropSpacePrefix :: [String] -> [String]
156+dropSpacePrefix lns =
157+ map (drop maxIndent) lns
158+ where flns = filter (not . all (== ' ')) lns
159+ maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns
160+
161+atStart :: PandocMonad m => MuseParser m a -> MuseParser m a
162+atStart p = do
163+ pos <- getPosition
164+ st <- getState
165+ guard $ museLastStrPos st /= Just pos
166+ p
142167
168+-- * Parsers
169+
170+-- | Parse end-of-line, which can be either a newline or end-of-file.
143171eol :: Stream s m Char => ParserT s st m ()
144172eol = void newline <|> eof
145173
146−htmlElement :: PandocMonad m => String -> MuseParser m (Attr, String)
174+someUntil :: (Stream s m t)
175+ => ParserT s u m a
176+ -> ParserT s u m b
177+ -> ParserT s u m ([a], b)
178+someUntil p end = first <$> ((:) <$> p) <*> manyUntil p end
179+
180+-- ** HTML parsers
181+
182+-- | Parse HTML tag, returning its attributes and literal contents.
183+htmlElement :: PandocMonad m
184+ => String -- ^ Tag name
185+ -> MuseParser m (Attr, String)
147186htmlElement tag = try $ do
148187 (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
149188 content <- manyTill anyChar endtag
@@ -151,12 +190,16 @@ htmlElement tag = try $ do
151190 where
152191 endtag = void $ htmlTag (~== TagClose tag)
153192
154−htmlBlock :: PandocMonad m => String -> MuseParser m (Attr, String)
193+htmlBlock :: PandocMonad m
194+ => String -- ^ Tag name
195+ -> MuseParser m (Attr, String)
155196htmlBlock tag = try $ do
197+ many spaceChar
156198 res <- htmlElement tag
157199 manyTill spaceChar eol
158200 return res
159201
202+-- | Convert HTML attributes to Pandoc 'Attr'
160203htmlAttrToPandoc :: [Attribute String] -> Attr
161204htmlAttrToPandoc attrs = (ident, classes, keyvals)
162205 where
@@ -165,48 +208,24 @@ htmlAttrToPandoc attrs = (ident, classes, keyvals)
165208 keyvals = [(k,v) | (k,v) <- attrs, k /= "id" && k /= "class"]
166209
167210parseHtmlContent :: PandocMonad m
168− => String -> MuseParser m (Attr, F Blocks)
169−parseHtmlContent tag = do
211+ => String -- ^ Tag name
212+ -> MuseParser m (Attr, F Blocks)
213+parseHtmlContent tag = try $ do
214+ many spaceChar
215+ pos <- getPosition
170216 (TagOpen _ attr, _) <- htmlTag (~== TagOpen tag [])
171217 manyTill spaceChar eol
172− content <- parseBlocksTill (manyTill spaceChar endtag)
218+ content <- parseBlocksTill $ try $ count (sourceColumn pos - 1) spaceChar >> endtag
173219 manyTill spaceChar eol -- closing tag must be followed by optional whitespace and newline
174220 return (htmlAttrToPandoc attr, content)
175221 where
176222 endtag = void $ htmlTag (~== TagClose tag)
177223
178−commonPrefix :: String -> String -> String
179−commonPrefix _ [] = []
180−commonPrefix [] _ = []
181−commonPrefix (x:xs) (y:ys)
182− | x == y = x : commonPrefix xs ys
183− | otherwise = []
184−
185−atStart :: PandocMonad m => MuseParser m a -> MuseParser m a
186−atStart p = do
187− pos <- getPosition
188− st <- getState
189− guard $ museLastStrPos st /= Just pos
190− p
191−
192−someUntil :: (Stream s m t)
193− => ParserT s u m a
194− -> ParserT s u m b
195− -> ParserT s u m ([a], b)
196−someUntil p end = do
197− first <- p
198− (rest, e) <- manyUntil p end
199− return (first:rest, e)
200−
201−--
202−-- directive parsers
203−--
224+-- ** Directive parsers
204225
205226-- While not documented, Emacs Muse allows "-" in directive name
206227parseDirectiveKey :: PandocMonad m => MuseParser m String
207−parseDirectiveKey = do
208− char '#'
209− many (letter <|> char '-')
228+parseDirectiveKey = char '#' *> many (letter <|> char '-')
210229
211230parseEmacsDirective :: PandocMonad m => MuseParser m (String, F Inlines)
212231parseEmacsDirective = do
@@ -233,55 +252,42 @@ directive = do
233252 where translateKey "cover" = "cover-image"
234253 translateKey x = x
235254
236−--
237−-- block parsers
238−--
255+-- ** Block parsers
239256
240257parseBlocks :: PandocMonad m
241258 => MuseParser m (F Blocks)
242259parseBlocks =
243− try parseEnd <|>
244− try blockStart <|>
245− try listStart <|>
246− try paraStart
260+ try (parseEnd <|>
261+ blockStart <|>
262+ listStart <|>
263+ paraStart)
247264 where
248265 parseEnd = mempty <$ eof
249− blockStart = do first <- header <|> blockElements <|> emacsNoteBlock
250− rest <- parseBlocks
251− return $ first B.<> rest
266+ blockStart = ((B.<>) <$> (emacsHeading <|> blockElements <|> emacsNoteBlock)
267+ <*> parseBlocks) <|> (uncurry (B.<>) <$> amuseHeadingUntil parseBlocks)
252268 listStart = do
253269 updateState (\st -> st { museInPara = False })
254− (first, rest) <- anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks
255− return $ first B.<> rest
270+ uncurry (B.<>) <$> (anyListUntil parseBlocks <|> amuseNoteBlockUntil parseBlocks)
256271 paraStart = do
257272 indent <- length <$> many spaceChar
258− (first, rest) <- paraUntil parseBlocks
259− let first' = if indent >= 2 && indent < 6 then B.blockQuote <$> first else first
260− return $ first' B.<> rest
273+ uncurry (B.<>) . first (p indent) <$> paraUntil parseBlocks
274+ where p indent = if indent >= 2 && indent < 6 then fmap B.blockQuote else id
261275
262276parseBlocksTill :: PandocMonad m
263277 => MuseParser m a
264278 -> MuseParser m (F Blocks)
265279parseBlocksTill end =
266− try parseEnd <|>
267− try blockStart <|>
268− try listStart <|>
269− try paraStart
280+ try (parseEnd <|>
281+ blockStart <|>
282+ listStart <|>
283+ paraStart)
270284 where
271285 parseEnd = mempty <$ end
272− blockStart = do first <- blockElements
273− rest <- continuation
274− return $ first B.<> rest
286+ blockStart = (B.<>) <$> blockElements <*> continuation
275287 listStart = do
276288 updateState (\st -> st { museInPara = False })
277− (first, e) <- anyListUntil ((Left <$> end) <|> (Right <$> continuation))
278− case e of
279− Left _ -> return first
280− Right rest -> return $ first B.<> rest
281− paraStart = do (first, e) <- paraUntil ((Left <$> end) <|> (Right <$> continuation))
282− case e of
283− Left _ -> return first
284− Right rest -> return $ first B.<> rest
289+ uncurry (B.<>) <$> anyListUntil (parseEnd <|> continuation)
290+ paraStart = uncurry (B.<>) <$> paraUntil (parseEnd <|> continuation)
285291 continuation = parseBlocksTill end
286292
287293listItemContentsUntil :: PandocMonad m
@@ -294,24 +300,17 @@ listItemContentsUntil col pre end =
294300 try listStart <|>
295301 try paraStart
296302 where
297− parsePre = do e <- pre
298− return (mempty, e)
299− parseEnd = do e <- end
300− return (mempty, e)
303+ parsePre = (mempty,) <$> pre
304+ parseEnd = (mempty,) <$> end
301305 paraStart = do
302− (first, e) <- paraUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
303− case e of
304− Left ee -> return (first, ee)
305− Right (rest, ee) -> return (first B.<> rest, ee)
306− blockStart = do first <- blockElements
307− (rest, e) <- parsePre <|> continuation <|> parseEnd
308− return (first B.<> rest, e)
306+ (f, (r, e)) <- paraUntil (parsePre <|> continuation <|> parseEnd)
307+ return (f B.<> r, e)
308+ blockStart = first <$> ((B.<>) <$> blockElements)
309+ <*> (parsePre <|> continuation <|> parseEnd)
309310 listStart = do
310311 updateState (\st -> st { museInPara = False })
311− (first, e) <- anyListUntil ((Left <$> pre) <|> (Right <$> continuation) <|> (Left <$> end))
312− case e of
313− Left ee -> return (first, ee)
314− Right (rest, ee) -> return (first B.<> rest, ee)
312+ (f, (r, e)) <- anyListUntil (parsePre <|> continuation <|> parseEnd)
313+ return (f B.<> r, e)
315314 continuation = try $ do blank <- optionMaybe blankline
316315 skipMany blankline
317316 indentWith col
@@ -338,19 +337,24 @@ blockElements = do
338337 , rightTag
339338 , quoteTag
340339 , divTag
340+ , biblioTag
341+ , playTag
341342 , verseTag
342343 , lineBlock
343344 , table
344345 , commentTag
345346 ]
346347
348+-- | Parse a line comment, starting with @;@ in the first column.
347349comment :: PandocMonad m => MuseParser m (F Blocks)
348350comment = try $ do
351+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
349352 char ';'
350353 optional (spaceChar >> many (noneOf "\n"))
351354 eol
352355 return mempty
353356
357+-- | Parse a horizontal rule, consisting of 4 or more @\'-\'@ characters.
354358separator :: PandocMonad m => MuseParser m (F Blocks)
355359separator = try $ do
356360 string "----"
@@ -359,17 +363,37 @@ separator = try $ do
359363 eol
360364 return $ return B.horizontalRule
361365
362−header :: PandocMonad m => MuseParser m (F Blocks)
363−header = try $ do
366+-- | Parse a single-line heading.
367+emacsHeading :: PandocMonad m => MuseParser m (F Blocks)
368+emacsHeading = try $ do
369+ guardDisabled Ext_amuse
370+ anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol)
364371 getPosition >>= \pos -> guard (sourceColumn pos == 1)
365372 level <- fmap length $ many1 $ char '*'
366373 guard $ level <= 5
367374 spaceChar
368375 content <- trimInlinesF . mconcat <$> manyTill inline eol
369− anchorId <- option "" parseAnchor
370376 attr <- registerHeader (anchorId, [], []) (runF content def)
371377 return $ B.headerWith attr level <$> content
372378
379+-- | Parse a multi-line heading.
380+-- It is a Text::Amuse extension, Emacs Muse does not allow heading to span multiple lines.
381+amuseHeadingUntil :: PandocMonad m
382+ => MuseParser m a -- ^ Terminator parser
383+ -> MuseParser m (F Blocks, a)
384+amuseHeadingUntil end = try $ do
385+ guardEnabled Ext_amuse
386+ anchorId <- option "" $ try (parseAnchor <* manyTill spaceChar eol)
387+ getPosition >>= \pos -> guard (sourceColumn pos == 1)
388+ level <- fmap length $ many1 $ char '*'
389+ guard $ level <= 5
390+ spaceChar
391+ (content, e) <- paraContentsUntil end
392+ attr <- registerHeader (anchorId, [], []) (runF content def)
393+ return (B.headerWith attr level <$> content, e)
394+
395+-- | Parse an example between @{{{@ and @}}}@.
396+-- It is an Amusewiki extension influenced by Creole wiki, as described in @Text::Amuse@ documentation.
373397example :: PandocMonad m => MuseParser m (F Blocks)
374398example = try $ do
375399 string "{{{"
@@ -377,57 +401,63 @@ example = try $ do
377401 contents <- manyTill anyChar $ try (optional blankline >> string "}}}")
378402 return $ return $ B.codeBlock contents
379403
380−-- Trim up to one newline from the beginning and the end,
381−-- in case opening and/or closing tags are on separate lines.
382−chop :: String -> String
383−chop = lchop . rchop
384−
385−lchop :: String -> String
386−lchop s = case s of
387− '\n':ss -> ss
388− _ -> s
389−
390−rchop :: String -> String
391−rchop = reverse . lchop . reverse
392−
393−dropSpacePrefix :: [String] -> [String]
394−dropSpacePrefix lns =
395− map (drop maxIndent) lns
396− where flns = filter (not . all (== ' ')) lns
397− maxIndent = if null flns then maximum (map length lns) else length $ takeWhile (== ' ') $ foldl1 commonPrefix flns
398−
404+-- | Parse an @\<example>@ tag.
399405exampleTag :: PandocMonad m => MuseParser m (F Blocks)
400406exampleTag = try $ do
401− many spaceChar
402407 (attr, contents) <- htmlBlock "example"
403408 return $ return $ B.codeBlockWith attr $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop contents
404409
410+-- | Parse a @\<literal>@ tag as a raw block.
411+-- For 'RawInline' @\<literal>@ parser, see 'inlineLiteralTag'.
405412literalTag :: PandocMonad m => MuseParser m (F Blocks)
406−literalTag = do
407− guardDisabled Ext_amuse -- Text::Amuse does not support <literal>
408− (return . rawBlock) <$> htmlBlock "literal"
413+literalTag = try $ do
414+ many spaceChar
415+ (TagOpen _ attr, _) <- htmlTag (~== TagOpen "literal" [])
416+ manyTill spaceChar eol
417+ content <- manyTill anyChar endtag
418+ manyTill spaceChar eol
419+ return $ return $ rawBlock (htmlAttrToPandoc attr, content)
409420 where
421+ endtag = void $ htmlTag (~== TagClose "literal")
410422 -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
411423 format (_, _, kvs) = fromMaybe "html" $ lookup "style" kvs
412− rawBlock (attrs, content) = B.rawBlock (format attrs) $ chop content
424+ rawBlock (attrs, content) = B.rawBlock (format attrs) $ rchop $ intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content
413425
414−-- <center> tag is ignored
426+-- | Parse @\<center>@ tag.
427+-- Currently it is ignored as Pandoc cannot represent centered blocks.
415428centerTag :: PandocMonad m => MuseParser m (F Blocks)
416429centerTag = snd <$> parseHtmlContent "center"
417430
418−-- <right> tag is ignored
431+-- | Parse @\<right>@ tag.
432+-- Currently it is ignored as Pandoc cannot represent centered blocks.
419433rightTag :: PandocMonad m => MuseParser m (F Blocks)
420434rightTag = snd <$> parseHtmlContent "right"
421435
436+-- | Parse @\<quote>@ tag.
422437quoteTag :: PandocMonad m => MuseParser m (F Blocks)
423438quoteTag = fmap B.blockQuote . snd <$> parseHtmlContent "quote"
424439
425−-- <div> tag is supported by Emacs Muse, but not Amusewiki 2.025
440+-- | Parse @\<div>@ tag.
441+-- @\<div>@ tag is supported by Emacs Muse, but not Amusewiki 2.025.
426442divTag :: PandocMonad m => MuseParser m (F Blocks)
427443divTag = do
428444 (attrs, content) <- parseHtmlContent "div"
429445 return $ B.divWith attrs <$> content
430446
447+-- | Parse @\<biblio>@ tag, the result is the same as @\<div class="biblio">@.
448+-- @\<biblio>@ tag is supported only in Text::Amuse mode.
449+biblioTag :: PandocMonad m => MuseParser m (F Blocks)
450+biblioTag = do
451+ guardEnabled Ext_amuse
452+ fmap (B.divWith ("", ["biblio"], [])) . snd <$> parseHtmlContent "biblio"
453+
454+-- | Parse @\<play>@ tag, the result is the same as @\<div class="play">@.
455+-- @\<play>@ tag is supported only in Text::Amuse mode.
456+playTag :: PandocMonad m => MuseParser m (F Blocks)
457+playTag = do
458+ guardEnabled Ext_amuse
459+ fmap (B.divWith ("", ["play"], [])) . snd <$> parseHtmlContent "play"
460+
431461verseLine :: PandocMonad m => MuseParser m (F Inlines)
432462verseLine = do
433463 indent <- (B.str <$> many1 (char ' ' >> pure '\160')) <|> pure mempty
@@ -439,32 +469,39 @@ verseLines = do
439469 lns <- many verseLine
440470 return $ B.lineBlock <$> sequence lns
441471
472+-- | Parse @\<verse>@ tag.
442473verseTag :: PandocMonad m => MuseParser m (F Blocks)
443474verseTag = do
444475 (_, content) <- htmlBlock "verse"
445476 parseFromString verseLines (intercalate "\n" $ dropSpacePrefix $ splitOn "\n" $ lchop content)
446477
478+-- | Parse @\<comment>@ tag.
447479commentTag :: PandocMonad m => MuseParser m (F Blocks)
448480commentTag = htmlBlock "comment" >> return mempty
449481
450−-- Indented paragraph is either center, right or quote
482+-- | Parse paragraph contents.
483+paraContentsUntil :: PandocMonad m
484+ => MuseParser m a -- ^ Terminator parser
485+ -> MuseParser m (F Inlines, a)
486+paraContentsUntil end = do
487+ updateState (\st -> st { museInPara = True })
488+ (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end)
489+ updateState (\st -> st { museInPara = False })
490+ return (trimInlinesF $ mconcat l, e)
491+
492+-- | Parse a paragraph.
451493paraUntil :: PandocMonad m
452− => MuseParser m a
494+ => MuseParser m a -- ^ Terminator parser
453495 -> MuseParser m (F Blocks, a)
454496paraUntil end = do
455497 state <- getState
456498 guard $ not $ museInPara state
457− setState $ state{ museInPara = True }
458− (l, e) <- someUntil inline $ try (manyTill spaceChar eol >> end)
459− updateState (\st -> st { museInPara = False })
460− return (fmap B.para $ trimInlinesF $ mconcat l, e)
499+ first (fmap B.para) <$> paraContentsUntil end
461500
462501noteMarker :: PandocMonad m => MuseParser m String
463502noteMarker = try $ do
464503 char '['
465− first <- oneOf "123456789"
466− rest <- manyTill digit (char ']')
467− return $ first:rest
504+ (:) <$> oneOf "123456789" <*> manyTill digit (char ']')
468505
469506-- Amusewiki version of note
470507-- Parsing is similar to list item, except that note marker is used instead of list marker
@@ -473,14 +510,13 @@ amuseNoteBlockUntil :: PandocMonad m
473510 -> MuseParser m (F Blocks, a)
474511amuseNoteBlockUntil end = try $ do
475512 guardEnabled Ext_amuse
476− pos <- getPosition
477513 ref <- noteMarker <* spaceChar
514+ pos <- getPosition
478515 updateState (\st -> st { museInPara = False })
479− (content, e) <- listItemContentsUntil (sourceColumn pos) (fail "x") end
516+ (content, e) <- listItemContentsUntil (sourceColumn pos - 1) (fail "x") end
480517 oldnotes <- museNotes <$> getState
481− case M.lookup ref oldnotes of
482− Just _ -> logMessage $ DuplicateNoteReference ref pos
483− Nothing -> return ()
518+ when (M.member ref oldnotes)
519+ (logMessage $ DuplicateNoteReference ref pos)
484520 updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
485521 return (mempty, e)
486522
@@ -493,9 +529,8 @@ emacsNoteBlock = try $ do
493529 ref <- noteMarker <* skipSpaces
494530 content <- mconcat <$> blocksTillNote
495531 oldnotes <- museNotes <$> getState
496− case M.lookup ref oldnotes of
497− Just _ -> logMessage $ DuplicateNoteReference ref pos
498− Nothing -> return ()
532+ when (M.member ref oldnotes)
533+ (logMessage $ DuplicateNoteReference ref pos)
499534 updateState $ \s -> s{ museNotes = M.insert ref (pos, content) oldnotes }
500535 return mempty
501536 where
@@ -509,9 +544,10 @@ emacsNoteBlock = try $ do
509544lineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
510545lineVerseLine = try $ do
511546 string "> "
512− indent <- B.str <$> many (char ' ' >> pure '\160')
547+ indent <- many (char ' ' >> pure '\160')
548+ let indentEl = if null indent then mempty else B.str indent
513549 rest <- manyTill (choice inlineList) eol
514− return $ trimInlinesF $ mconcat (pure indent : rest)
550+ return $ trimInlinesF $ mconcat (pure indentEl : rest)
515551
516552blanklineVerseLine :: PandocMonad m => MuseParser m (F Inlines)
517553blanklineVerseLine = try $ do
@@ -519,29 +555,28 @@ blanklineVerseLine = try $ do
519555 blankline
520556 pure mempty
521557
558+-- | Parse a line block indicated by @\'>\'@ characters.
522559lineBlock :: PandocMonad m => MuseParser m (F Blocks)
523560lineBlock = try $ do
561+ many spaceChar
524562 col <- sourceColumn <$> getPosition
525563 lns <- (blanklineVerseLine <|> lineVerseLine) `sepBy1'` try (indentWith (col - 1))
526564 return $ B.lineBlock <$> sequence lns
527565
528−--
529−-- lists
530−--
566+-- *** List parsers
531567
532568bulletListItemsUntil :: PandocMonad m
533− => Int
534− -> MuseParser m a
569+ => Int -- ^ Indentation
570+ -> MuseParser m a -- ^ Terminator parser
535571 -> MuseParser m ([F Blocks], a)
536572bulletListItemsUntil indent end = try $ do
537573 char '-'
538574 void spaceChar <|> lookAhead eol
539575 updateState (\st -> st { museInPara = False })
540− (x, e) <- listItemContentsUntil (indent + 2) (Right <$> try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (Left <$> end)
541− case e of
542− Left ee -> return ([x], ee)
543− Right (xs, ee) -> return (x:xs, ee)
576+ (x, (xs, e)) <- listItemContentsUntil (indent + 2) (try (optional blankline >> indentWith indent >> bulletListItemsUntil indent end)) (([],) <$> end)
577+ return (x:xs, e)
544578
579+-- | Parse a bullet list.
545580bulletListUntil :: PandocMonad m
546581 => MuseParser m a
547582 -> MuseParser m (F Blocks, a)
@@ -563,16 +598,15 @@ anyMuseOrderedListMarker = do
563598museOrderedListMarker :: PandocMonad m
564599 => ListNumberStyle
565600 -> MuseParser m Int
566−museOrderedListMarker style = do
567− (_, start) <- case style of
568− Decimal -> decimal
569− UpperRoman -> upperRoman
570− LowerRoman -> lowerRoman
571− UpperAlpha -> upperAlpha
572− LowerAlpha -> lowerAlpha
573− _ -> fail "Unhandled case"
574− char '.'
575− return start
601+museOrderedListMarker style =
602+ snd <$> p <* char '.'
603+ where p = case style of
604+ Decimal -> decimal
605+ UpperRoman -> upperRoman
606+ LowerRoman -> lowerRoman
607+ UpperAlpha -> upperAlpha
608+ LowerAlpha -> lowerAlpha
609+ _ -> fail "Unhandled case"
576610
577611orderedListItemsUntil :: PandocMonad m
578612 => Int
@@ -586,11 +620,10 @@ orderedListItemsUntil indent style end =
586620 pos <- getPosition
587621 void spaceChar <|> lookAhead eol
588622 updateState (\st -> st { museInPara = False })
589− (x, e) <- listItemContentsUntil (sourceColumn pos) (Right <$> try (optionMaybe blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (Left <$> end)
590− case e of
591− Left ee -> return ([x], ee)
592− Right (xs, ee) -> return (x:xs, ee)
623+ (x, (xs, e)) <- listItemContentsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> museOrderedListMarker style >> continuation)) (([],) <$> end)
624+ return (x:xs, e)
593625
626+-- | Parse an ordered list.
594627orderedListUntil :: PandocMonad m
595628 => MuseParser m a
596629 -> MuseParser m (F Blocks, a)
@@ -611,10 +644,8 @@ descriptionsUntil :: PandocMonad m
611644descriptionsUntil indent end = do
612645 void spaceChar <|> lookAhead eol
613646 updateState (\st -> st { museInPara = False })
614− (x, e) <- listItemContentsUntil indent (Right <$> try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (Left <$> end)
615− case e of
616− Right (xs, ee) -> return (x:xs, ee)
617− Left ee -> return ([x], ee)
647+ (x, (xs, e)) <- listItemContentsUntil indent (try (optional blankline >> indentWith indent >> manyTill spaceChar (string "::") >> descriptionsUntil indent end)) (([],) <$> end)
648+ return (x:xs, e)
618649
619650definitionListItemsUntil :: PandocMonad m
620651 => Int
@@ -625,37 +656,31 @@ definitionListItemsUntil indent end =
625656 where
626657 continuation = try $ do
627658 pos <- getPosition
628− term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (string "::")
629− (x, e) <- descriptionsUntil (sourceColumn pos) ((Right <$> try (optional blankline >> indentWith indent >> continuation)) <|> (Left <$> end))
630− let xx = do
631− term' <- term
632− x' <- sequence x
633− return (term', x')
634− case e of
635− Left ee -> return ([xx], ee)
636− Right (xs, ee) -> return (xx:xs, ee)
659+ term <- trimInlinesF . mconcat <$> manyTill (choice inlineList) (try $ string "::")
660+ (x, (xs, e)) <- descriptionsUntil (sourceColumn pos) (try (optional blankline >> indentWith indent >> continuation) <|> (([],) <$> end))
661+ let xx = (,) <$> term <*> sequence x
662+ return (xx:xs, e)
637663
664+-- | Parse a definition list.
638665definitionListUntil :: PandocMonad m
639− => MuseParser m a
666+ => MuseParser m a -- ^ Terminator parser
640667 -> MuseParser m (F Blocks, a)
641668definitionListUntil end = try $ do
642669 many spaceChar
643670 pos <- getPosition
644671 let indent = sourceColumn pos - 1
645672 guardDisabled Ext_amuse <|> guard (indent /= 0) -- Initial space is required by Amusewiki, but not Emacs Muse
646− (items, e) <- definitionListItemsUntil indent end
647− return (B.definitionList <$> sequence items, e)
673+ first (fmap B.definitionList . sequence) <$> definitionListItemsUntil indent end
648674
649675anyListUntil :: PandocMonad m
650− => MuseParser m a
676+ => MuseParser m a -- ^ Terminator parser
651677 -> MuseParser m (F Blocks, a)
652678anyListUntil end =
653679 bulletListUntil end <|> orderedListUntil end <|> definitionListUntil end
654680
655−--
656−-- tables
657−--
681+-- *** Table parsers
658682
683+-- | Internal Muse table representation.
659684data MuseTable = MuseTable
660685 { museTableCaption :: Inlines
661686 , museTableHeaders :: [[Blocks]]
@@ -663,10 +688,10 @@ data MuseTable = MuseTable
663688 , museTableFooters :: [[Blocks]]
664689 }
665690
666−data MuseTableElement = MuseHeaderRow (F [Blocks])
667− | MuseBodyRow (F [Blocks])
668− | MuseFooterRow (F [Blocks])
669− | MuseCaption (F Inlines)
691+data MuseTableElement = MuseHeaderRow [Blocks]
692+ | MuseBodyRow [Blocks]
693+ | MuseFooterRow [Blocks]
694+ | MuseCaption Inlines
670695
671696museToPandocTable :: MuseTable -> Blocks
672697museToPandocTable (MuseTable caption headers body footers) =
@@ -676,73 +701,66 @@ museToPandocTable (MuseTable caption headers body footers) =
676701 headRow = if null headers then [] else head headers
677702 rows = (if null headers then [] else tail headers) ++ body ++ footers
678703
679−museAppendElement :: MuseTable
680− -> MuseTableElement
681− -> F MuseTable
682−museAppendElement tbl element =
704+museAppendElement :: MuseTableElement
705+ -> MuseTable
706+ -> MuseTable
707+museAppendElement element tbl =
683708 case element of
684− MuseHeaderRow row -> do
685− row' <- row
686− return tbl{ museTableHeaders = museTableHeaders tbl ++ [row'] }
687− MuseBodyRow row -> do
688− row' <- row
689− return tbl{ museTableRows = museTableRows tbl ++ [row'] }
690− MuseFooterRow row-> do
691− row' <- row
692− return tbl{ museTableFooters = museTableFooters tbl ++ [row'] }
693− MuseCaption inlines -> do
694− inlines' <- inlines
695− return tbl{ museTableCaption = inlines' }
709+ MuseHeaderRow row -> tbl{ museTableHeaders = row : museTableHeaders tbl }
710+ MuseBodyRow row -> tbl{ museTableRows = row : museTableRows tbl }
711+ MuseFooterRow row -> tbl{ museTableFooters = row : museTableFooters tbl }
712+ MuseCaption inlines -> tbl{ museTableCaption = inlines }
696713
697714tableCell :: PandocMonad m => MuseParser m (F Blocks)
698715tableCell = try $ fmap B.plain . trimInlinesF . mconcat <$> manyTill inline (lookAhead cellEnd)
699716 where cellEnd = try $ void (many1 spaceChar >> char '|') <|> eol
700717
701−tableElements :: PandocMonad m => MuseParser m [MuseTableElement]
702−tableElements = tableParseElement `sepEndBy1` eol
718+tableElements :: PandocMonad m => MuseParser m (F [MuseTableElement])
719+tableElements = sequence <$> (tableParseElement `sepEndBy1` eol)
703720
704−elementsToTable :: [MuseTableElement] -> F MuseTable
705−elementsToTable = foldM museAppendElement emptyTable
721+elementsToTable :: [MuseTableElement] -> MuseTable
722+elementsToTable = foldr museAppendElement emptyTable
706723 where emptyTable = MuseTable mempty mempty mempty mempty
707724
725+-- | Parse a table.
708726table :: PandocMonad m => MuseParser m (F Blocks)
709−table = try $ do
710− rows <- tableElements
711− let tbl = elementsToTable rows
712− let pandocTbl = museToPandocTable <$> tbl :: F Blocks
713− return pandocTbl
727+table = try $ fmap (museToPandocTable . elementsToTable) <$> tableElements
714728
715−tableParseElement :: PandocMonad m => MuseParser m MuseTableElement
729+tableParseElement :: PandocMonad m => MuseParser m (F MuseTableElement)
716730tableParseElement = tableParseHeader
717731 <|> tableParseBody
718732 <|> tableParseFooter
719733 <|> tableParseCaption
720734
721−tableParseRow :: PandocMonad m => Int -> MuseParser m (F [Blocks])
735+tableParseRow :: PandocMonad m
736+ => Int -- ^ Number of separator characters
737+ -> MuseParser m (F [Blocks])
722738tableParseRow n = try $ do
723739 fields <- tableCell `sepBy2` fieldSep
724740 return $ sequence fields
725741 where p `sepBy2` sep = (:) <$> p <*> many1 (sep >> p)
726742 fieldSep = many1 spaceChar >> count n (char '|') >> (void (many1 spaceChar) <|> void (lookAhead newline))
727743
728−tableParseHeader :: PandocMonad m => MuseParser m MuseTableElement
729−tableParseHeader = MuseHeaderRow <$> tableParseRow 2
744+-- | Parse a table header row.
745+tableParseHeader :: PandocMonad m => MuseParser m (F MuseTableElement)
746+tableParseHeader = fmap MuseHeaderRow <$> tableParseRow 2
730747
731−tableParseBody :: PandocMonad m => MuseParser m MuseTableElement
732−tableParseBody = MuseBodyRow <$> tableParseRow 1
748+-- | Parse a table body row.
749+tableParseBody :: PandocMonad m => MuseParser m (F MuseTableElement)
750+tableParseBody = fmap MuseBodyRow <$> tableParseRow 1
733751
734−tableParseFooter :: PandocMonad m => MuseParser m MuseTableElement
735−tableParseFooter = MuseFooterRow <$> tableParseRow 3
752+-- | Parse a table footer row.
753+tableParseFooter :: PandocMonad m => MuseParser m (F MuseTableElement)
754+tableParseFooter = fmap MuseFooterRow <$> tableParseRow 3
736755
737−tableParseCaption :: PandocMonad m => MuseParser m MuseTableElement
756+-- | Parse table caption.
757+tableParseCaption :: PandocMonad m => MuseParser m (F MuseTableElement)
738758tableParseCaption = try $ do
739759 many spaceChar
740760 string "|+"
741− MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|"))
761+ fmap MuseCaption <$> (trimInlinesF . mconcat <$> many1Till inline (string "+|"))
742762
743−--
744−-- inline parsers
745−--
763+-- ** Inline parsers
746764
747765inlineList :: PandocMonad m => [MuseParser m (F Inlines)]
748766inlineList = [ whitespace
@@ -758,10 +776,12 @@ inlineList = [ whitespace
758776 , subscriptTag
759777 , strikeoutTag
760778 , verbatimTag
779+ , classTag
761780 , nbsp
762781 , link
763782 , code
764783 , codeTag
784+ , mathTag
765785 , inlineLiteralTag
766786 , str
767787 , symbol
@@ -770,28 +790,30 @@ inlineList = [ whitespace
770790inline :: PandocMonad m => MuseParser m (F Inlines)
771791inline = endline <|> choice inlineList <?> "inline"
772792
793+-- | Parse a soft break.
773794endline :: PandocMonad m => MuseParser m (F Inlines)
774795endline = try $ do
775796 newline
776797 notFollowedBy blankline
777− returnF B.softbreak
798+ return $ return B.softbreak
778799
779800parseAnchor :: PandocMonad m => MuseParser m String
780801parseAnchor = try $ do
781802 getPosition >>= \pos -> guard (sourceColumn pos == 1)
782803 char '#'
783− first <- letter
784− rest <- many (letter <|> digit)
785− skipMany spaceChar <|> void newline
786− return $ first:rest
804+ (:) <$> letter <*> many (letter <|> digit <|> char '-')
787805
788806anchor :: PandocMonad m => MuseParser m (F Inlines)
789807anchor = try $ do
790808 anchorId <- parseAnchor
809+ skipMany spaceChar <|> void newline
791810 return $ return $ B.spanWith (anchorId, [], []) mempty
792811
812+-- | Parse a footnote reference.
793813footnote :: PandocMonad m => MuseParser m (F Inlines)
794814footnote = try $ do
815+ inLink <- museInLink <$> getState
816+ guard $ not inLink
795817 ref <- noteMarker
796818 return $ do
797819 notes <- asksF museNotes
@@ -799,7 +821,7 @@ footnote = try $ do
799821 Nothing -> return $ B.str $ "[" ++ ref ++ "]"
800822 Just (_pos, contents) -> do
801823 st <- askF
802− let contents' = runF contents st { museNotes = M.empty }
824+ let contents' = runF contents st { museNotes = M.delete ref (museNotes st) }
803825 return $ B.note contents'
804826
805827whitespace :: PandocMonad m => MuseParser m (F Inlines)
@@ -807,6 +829,7 @@ whitespace = try $ do
807829 skipMany1 spaceChar
808830 return $ return B.space
809831
832+-- | Parse @\<br>@ tag.
810833br :: PandocMonad m => MuseParser m (F Inlines)
811834br = try $ do
812835 string "<br>"
@@ -822,49 +845,68 @@ enclosedInlines :: (PandocMonad m, Show a, Show b)
822845enclosedInlines start end = try $
823846 trimInlinesF . mconcat <$> (enclosed (atStart start) end inline <* notFollowedBy (satisfy isLetter))
824847
848+-- | Parse an inline tag, such as @\<em>@ and @\<strong>@.
825849inlineTag :: PandocMonad m
826− => (Inlines -> Inlines)
827− -> String
850+ => String -- ^ Tag name
828851 -> MuseParser m (F Inlines)
829−inlineTag f tag = try $ do
852+inlineTag tag = try $ do
830853 htmlTag (~== TagOpen tag [])
831− res <- manyTill inline (void $ htmlTag (~== TagClose tag))
832− return $ f <$> mconcat res
833−
834−strongTag :: PandocMonad m => MuseParser m (F Inlines)
835−strongTag = inlineTag B.strong "strong"
854+ mconcat <$> manyTill inline (void $ htmlTag (~== TagClose tag))
836855
856+-- | Parse strong inline markup, indicated by @**@.
837857strong :: PandocMonad m => MuseParser m (F Inlines)
838858strong = fmap B.strong <$> emphasisBetween (string "**")
839859
860+-- | Parse emphasis inline markup, indicated by @*@.
840861emph :: PandocMonad m => MuseParser m (F Inlines)
841862emph = fmap B.emph <$> emphasisBetween (char '*')
842863
864+-- | Parse underline inline markup, indicated by @_@.
865+-- Supported only in Emacs Muse mode, not Text::Amuse.
843866underlined :: PandocMonad m => MuseParser m (F Inlines)
844867underlined = do
845868 guardDisabled Ext_amuse -- Supported only by Emacs Muse
846869 fmap underlineSpan <$> emphasisBetween (char '_')
847870
871+-- | Parse @\<strong>@ tag.
872+strongTag :: PandocMonad m => MuseParser m (F Inlines)
873+strongTag = fmap B.strong <$> inlineTag "strong"
874+
875+-- | Parse @\<em>@ tag.
848876emphTag :: PandocMonad m => MuseParser m (F Inlines)
849−emphTag = inlineTag B.emph "em"
877+emphTag = fmap B.emph <$> inlineTag "em"
850878
879+-- | Parse @\<sup>@ tag.
851880superscriptTag :: PandocMonad m => MuseParser m (F Inlines)
852−superscriptTag = inlineTag B.superscript "sup"
881+superscriptTag = fmap B.superscript <$> inlineTag "sup"
853882
883+-- | Parse @\<sub>@ tag.
854884subscriptTag :: PandocMonad m => MuseParser m (F Inlines)
855−subscriptTag = inlineTag B.subscript "sub"
885+subscriptTag = fmap B.subscript <$> inlineTag "sub"
856886
887+-- | Parse @\<del>@ tag.
857888strikeoutTag :: PandocMonad m => MuseParser m (F Inlines)
858−strikeoutTag = inlineTag B.strikeout "del"
889+strikeoutTag = fmap B.strikeout <$> inlineTag "del"
859890
891+-- | Parse @\<verbatim>@ tag.
860892verbatimTag :: PandocMonad m => MuseParser m (F Inlines)
861893verbatimTag = return . B.text . snd <$> htmlElement "verbatim"
862894
895+-- | Parse @\<class>@ tag.
896+classTag :: PandocMonad m => MuseParser m (F Inlines)
897+classTag = do
898+ (TagOpen _ attrs, _) <- htmlTag (~== TagOpen "class" [])
899+ res <- manyTill inline (void $ htmlTag (~== TagClose "class"))
900+ let classes = maybe [] words $ lookup "name" attrs
901+ return $ B.spanWith ("", classes, []) <$> mconcat res
902+
903+-- | Parse "~~" as nonbreaking space.
863904nbsp :: PandocMonad m => MuseParser m (F Inlines)
864905nbsp = try $ do
865906 string "~~"
866907 return $ return $ B.str "\160"
867908
909+-- | Parse code markup, indicated by @\'=\'@ characters.
868910code :: PandocMonad m => MuseParser m (F Inlines)
869911code = try $ do
870912 atStart $ char '='
@@ -875,14 +917,18 @@ code = try $ do
875917 notFollowedBy $ satisfy isLetter
876918 return $ return $ B.code contents
877919
920+-- | Parse @\<code>@ tag.
878921codeTag :: PandocMonad m => MuseParser m (F Inlines)
879−codeTag = do
880− (attrs, content) <- htmlElement "code"
881− return $ return $ B.codeWith attrs content
922+codeTag = return . uncurry B.codeWith <$> htmlElement "code"
882923
924+-- | Parse @\<math>@ tag.
925+-- @\<math>@ tag is an Emacs Muse extension enabled by @(require 'muse-latex2png)@
926+mathTag :: PandocMonad m => MuseParser m (F Inlines)
927+mathTag = return . B.math . snd <$> htmlElement "math"
928+
929+-- | Parse inline @\<literal>@ tag as a raw inline.
883930inlineLiteralTag :: PandocMonad m => MuseParser m (F Inlines)
884−inlineLiteralTag = do
885− guardDisabled Ext_amuse -- Text::Amuse does not support <literal>
931+inlineLiteralTag =
886932 (return . rawInline) <$> htmlElement "literal"
887933 where
888934 -- FIXME: Emacs Muse inserts <literal> without style into all output formats, but we assume HTML
@@ -890,39 +936,35 @@ inlineLiteralTag = do
890936 rawInline (attrs, content) = B.rawInline (format attrs) content
891937
892938str :: PandocMonad m => MuseParser m (F Inlines)
893−str = do
894− result <- many1 alphaNum
895− updateLastStrPos
896− return $ return $ B.str result
939+str = return . B.str <$> many1 alphaNum <* updateLastStrPos
897940
898941symbol :: PandocMonad m => MuseParser m (F Inlines)
899942symbol = return . B.str <$> count 1 nonspaceChar
900943
944+-- | Parse a link or image.
901945link :: PandocMonad m => MuseParser m (F Inlines)
902946link = try $ do
903947 st <- getState
904948 guard $ not $ museInLink st
905949 setState $ st{ museInLink = True }
906− (url, title, content) <- linkText
950+ (url, content) <- linkText
907951 updateState (\state -> state { museInLink = False })
908952 return $ case stripPrefix "URL:" url of
909953 Nothing -> if isImageUrl url
910− then B.image url title <$> fromMaybe (return mempty) content
911− else B.link url title <$> fromMaybe (return $ B.str url) content
912− Just url' -> B.link url' title <$> fromMaybe (return $ B.str url') content
954+ then B.image url "" <$> fromMaybe (return mempty) content
955+ else B.link url "" <$> fromMaybe (return $ B.str url) content
956+ Just url' -> B.link url' "" <$> fromMaybe (return $ B.str url') content
913957 where -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
914958 imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
915959 isImageUrl = (`elem` imageExtensions) . takeExtension
916960
917961linkContent :: PandocMonad m => MuseParser m (F Inlines)
918−linkContent = do
919− char '['
920− trimInlinesF . mconcat <$> many1Till inline (string "]")
962+linkContent = char '[' >> trimInlinesF . mconcat <$> manyTill inline (string "]")
921963
922−linkText :: PandocMonad m => MuseParser m (String, String, Maybe (F Inlines))
964+linkText :: PandocMonad m => MuseParser m (String, Maybe (F Inlines))
923965linkText = do
924966 string "[["
925− url <- many1Till anyChar $ char ']'
967+ url <- manyTill anyChar $ char ']'
926968 content <- optionMaybe linkContent
927969 char ']'
928− return (url, "", content)
970+ return (url, content)
src/Text/Pandoc/Readers/Native.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -30,6 +31,7 @@ Conversion of a string representation of a pandoc type (@Pandoc@,
3031-}
3132module Text.Pandoc.Readers.Native ( readNative ) where
3233
34+import Prelude
3335import Text.Pandoc.Definition
3436import Text.Pandoc.Options (ReaderOptions)
3537import Text.Pandoc.Shared (safeRead)
src/Text/Pandoc/Readers/OPML.hs+32−1
@@ -1,5 +1,36 @@
1−{-# LANGUAGE FlexibleContexts #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-
3+Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
4+
5+This program is free software; you can redistribute it and/or modify
6+it under the terms of the GNU General Public License as published by
7+the Free Software Foundation; either version 2 of the License, or
8+(at your option) any later version.
9+
10+This program is distributed in the hope that it will be useful,
11+but WITHOUT ANY WARRANTY; without even the implied warranty of
12+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+GNU General Public License for more details.
14+
15+You should have received a copy of the GNU General Public License
16+along with this program; if not, write to the Free Software
17+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18+-}
19+
20+{- |
21+ Module : Text.Pandoc.Readers.OPML
22+ Copyright : Copyright (C) 2013-2018 John MacFarlane
23+ License : GNU GPL, version 2 or above
24+
25+ Maintainer : John MacFarlane <jgm@berkeley.edu>
26+ Stability : alpha
27+ Portability : portable
28+
29+Conversion of OPML to 'Pandoc' document.
30+-}
31+
232module Text.Pandoc.Readers.OPML ( readOPML ) where
33+import Prelude
334import Control.Monad.State.Strict
435import Data.Char (toUpper)
536import Data.Default
src/Text/Pandoc/Readers/Odt.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE PatternGuards #-}
23
34{-
@@ -32,6 +33,7 @@ Entry point to the odt reader.
3233
3334module Text.Pandoc.Readers.Odt ( readOdt ) where
3435
36+import Prelude
3537import Codec.Archive.Zip
3638import qualified Text.XML.Light as XML
3739
src/Text/Pandoc/Readers/Odt/Arrows/State.hs+3−5
@@ -1,4 +1,4 @@
1−
1+{-# LANGUAGE NoImplicitPrelude #-}
22{-# LANGUAGE FlexibleInstances #-}
33{-# LANGUAGE TupleSections #-}
44{-
@@ -38,15 +38,13 @@ faster and easier to implement this way.
3838
3939module Text.Pandoc.Readers.Odt.Arrows.State where
4040
41+import Prelude
4142import Prelude hiding (foldl, foldr)
4243
4344import Control.Arrow
4445import qualified Control.Category as Cat
4546import Control.Monad
4647
47−import Data.Foldable
48−import Data.Monoid
49−
5048import Text.Pandoc.Readers.Odt.Arrows.Utils
5149import Text.Pandoc.Readers.Odt.Generic.Fallible
5250
@@ -131,7 +129,7 @@ withSubStateF' unlift a = ArrowState go
131129-- and one with any function.
132130foldS :: (Foldable f, Monoid m) => ArrowState s x m -> ArrowState s (f x) m
133131foldS a = ArrowState $ \(s,f) -> foldr a' (s,mempty) f
134− where a' x (s',m) = second (m <>) $ runArrowState a (s',x)
132+ where a' x (s',m) = second (mappend m) $ runArrowState a (s',x)
135133
136134-- | Fold a state arrow through something 'Foldable'. Collect the results in a
137135-- 'MonadPlus'.
src/Text/Pandoc/Readers/Odt/Arrows/Utils.hs+6−4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
34
@@ -39,6 +40,7 @@ with an equivalent return value.
3940-- We export everything
4041module Text.Pandoc.Readers.Odt.Arrows.Utils where
4142
43+import Prelude
4244import Control.Arrow
4345import Control.Monad (join)
4446
@@ -61,13 +63,13 @@ and6 :: (Arrow a)
6163 => a b c0->a b c1->a b c2->a b c3->a b c4->a b c5
6264 -> a b (c0,c1,c2,c3,c4,c5 )
6365
64−and3 a b c = (and2 a b ) &&& c
66+and3 a b c = and2 a b &&& c
6567 >>^ \((z,y ) , x) -> (z,y,x )
66−and4 a b c d = (and3 a b c ) &&& d
68+and4 a b c d = and3 a b c &&& d
6769 >>^ \((z,y,x ) , w) -> (z,y,x,w )
68−and5 a b c d e = (and4 a b c d ) &&& e
70+and5 a b c d e = and4 a b c d &&& e
6971 >>^ \((z,y,x,w ) , v) -> (z,y,x,w,v )
70−and6 a b c d e f = (and5 a b c d e ) &&& f
72+and6 a b c d e f = and5 a b c d e &&& f
7173 >>^ \((z,y,x,w,v ) , u) -> (z,y,x,w,v,u )
7274
7375liftA2 :: (Arrow a) => (x -> y -> z) -> a b x -> a b y -> a b z
src/Text/Pandoc/Readers/Odt/Base.hs−2
@@ -1,5 +1,3 @@
1−
2−
31{-
42Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
53
src/Text/Pandoc/Readers/Odt/ContentReader.hs+5−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE Arrows #-}
23{-# LANGUAGE PatternGuards #-}
34{-# LANGUAGE RecordWildCards #-}
@@ -39,6 +40,7 @@ module Text.Pandoc.Readers.Odt.ContentReader
3940, read_body
4041) where
4142
43+import Prelude
4244import Control.Applicative hiding (liftA, liftA2, liftA3)
4345import Control.Arrow
4446
@@ -520,7 +522,7 @@ matchingElement :: (Monoid e)
520522matchingElement ns name reader = (ns, name, asResultAccumulator reader)
521523 where
522524 asResultAccumulator :: (ArrowChoice a, Monoid m) => a m m -> a m (Fallible m)
523− asResultAccumulator a = liftAsSuccess $ keepingTheValue a >>% (<>)
525+ asResultAccumulator a = liftAsSuccess $ keepingTheValue a >>% mappend
524526
525527--
526528matchChildContent' :: (Monoid result)
@@ -554,7 +556,7 @@ read_plain_text = fst ^&&& read_plain_text' >>% recover
554556 read_plain_text' = ( second ( arr extractText )
555557 >>^ spreadChoice >>?! second text
556558 )
557− >>?% (<>)
559+ >>?% mappend
558560 --
559561 extractText :: XML.Content -> Fallible String
560562 extractText (XML.Text cData) = succeedWith (XML.cdData cData)
@@ -565,7 +567,7 @@ read_text_seq = matchingElement NsText "sequence"
565567 $ matchChildContent [] read_plain_text
566568
567569
568−-- specifically. I honor that, although the current implementation of '(<>)'
570+-- specifically. I honor that, although the current implementation of 'mappend'
569571-- for 'Inlines' in "Text.Pandoc.Builder" will collapse them again.
570572-- The rational is to be prepared for future modifications.
571573read_spaces :: InlineMatcher
src/Text/Pandoc/Readers/Odt/Generic/Fallible.hs+4−4
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12
23
34{-
@@ -38,8 +39,7 @@ compatible instances of "ArrowChoice".
3839
3940-- We export everything
4041module Text.Pandoc.Readers.Odt.Generic.Fallible where
41−
42−import Data.Monoid ((<>))
42+import Prelude
4343
4444-- | Default for now. Will probably become a class at some point.
4545type Failure = ()
@@ -90,7 +90,7 @@ collapseEither (Right (Right x)) = Right x
9090-- (possibly combined) non-error. If both values represent an error, an error
9191-- is returned.
9292chooseMax :: (Monoid a, Monoid b) => Either a b -> Either a b -> Either a b
93−chooseMax = chooseMaxWith (<>)
93+chooseMax = chooseMaxWith mappend
9494
9595-- | If either of the values represents a non-error, the result is a
9696-- (possibly combined) non-error. If both values represent an error, an error
@@ -100,7 +100,7 @@ chooseMaxWith :: (Monoid a) => (b -> b -> b)
100100 -> Either a b
101101 -> Either a b
102102chooseMaxWith (><) (Right a) (Right b) = Right $ a >< b
103−chooseMaxWith _ (Left a) (Left b) = Left $ a <> b
103+chooseMaxWith _ (Left a) (Left b) = Left $ a `mappend` b
104104chooseMaxWith _ (Right a) _ = Right a
105105chooseMaxWith _ _ (Right b) = Right b
106106
src/Text/Pandoc/Readers/Odt/Generic/Namespaces.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
34
@@ -31,6 +32,7 @@ typesafe Haskell namespace identifiers and unsafe "real world" namespaces.
3132
3233module Text.Pandoc.Readers.Odt.Generic.Namespaces where
3334
35+import Prelude
3436import qualified Data.Map as M
3537
3638--
src/Text/Pandoc/Readers/Odt/Generic/SetMap.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
34
@@ -30,6 +31,7 @@ A map of values to sets of values.
3031
3132module Text.Pandoc.Readers.Odt.Generic.SetMap where
3233
34+import Prelude
3335import qualified Data.Map as M
3436import qualified Data.Set as S
3537
src/Text/Pandoc/Readers/Odt/Generic/Utils.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12
23
34{-# LANGUAGE TypeOperators #-}
@@ -51,6 +52,7 @@ module Text.Pandoc.Readers.Odt.Generic.Utils
5152, composition
5253) where
5354
55+import Prelude
5456import Control.Category (Category, (<<<), (>>>))
5557import qualified Control.Category as Cat (id)
5658import Control.Monad (msum)
src/Text/Pandoc/Readers/Odt/Generic/XMLConverter.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE Arrows #-}
23{-# LANGUAGE TupleSections #-}
34{-# LANGUAGE GADTs #-}
@@ -67,6 +68,7 @@ module Text.Pandoc.Readers.Odt.Generic.XMLConverter
6768, matchContent
6869) where
6970
71+import Prelude
7072import Control.Applicative hiding ( liftA, liftA2 )
7173import Control.Monad ( MonadPlus )
7274import Control.Arrow
src/Text/Pandoc/Readers/Odt/Namespaces.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2015 Martin Linnemann <theCodingMarlin@googlemail.com>
34
@@ -31,6 +32,7 @@ Namespaces used in odt files.
3132module Text.Pandoc.Readers.Odt.Namespaces ( Namespace (..)
3233 ) where
3334
35+import Prelude
3436import Data.List (isPrefixOf)
3537import qualified Data.Map as M (empty, insert)
3638import Data.Maybe (fromMaybe, listToMaybe)
src/Text/Pandoc/Readers/Odt/StyleReader.hs+8−6
@@ -1,5 +1,6 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
13{-# LANGUAGE Arrows #-}
2−
34{-# LANGUAGE RecordWildCards #-}
45{-# LANGUAGE TupleSections #-}
56
@@ -57,6 +58,7 @@ module Text.Pandoc.Readers.Odt.StyleReader
5758, readStylesAt
5859) where
5960
61+import Prelude
6062import Control.Applicative hiding (liftA, liftA2, liftA3)
6163import Control.Arrow
6264
@@ -80,7 +82,6 @@ import Text.Pandoc.Readers.Odt.Generic.XMLConverter
8082import Text.Pandoc.Readers.Odt.Base
8183import Text.Pandoc.Readers.Odt.Namespaces
8284
83−
8485readStylesAt :: XML.Element -> Fallible Styles
8586readStylesAt e = runConverter' readAllStyles mempty e
8687
@@ -183,13 +184,14 @@ data Styles = Styles
183184 deriving ( Show )
184185
185186-- Styles from a monoid under union
186−instance Monoid Styles where
187− mempty = Styles M.empty M.empty M.empty
188− mappend (Styles sBn1 dSm1 lsBn1)
189− (Styles sBn2 dSm2 lsBn2)
187+instance Semigroup Styles where
188+ (Styles sBn1 dSm1 lsBn1) <> (Styles sBn2 dSm2 lsBn2)
190189 = Styles (M.union sBn1 sBn2)
191190 (M.union dSm1 dSm2)
192191 (M.union lsBn1 lsBn2)
192+instance Monoid Styles where
193+ mempty = Styles M.empty M.empty M.empty
194+ mappend = (<>)
193195
194196-- Not all families from the specifications are implemented, only those we need.
195197-- But there are none that are not mentioned here.
src/Text/Pandoc/Readers/Org.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -27,6 +28,7 @@ Conversion of org-mode formatted plain text to 'Pandoc' document.
2728-}
2829module Text.Pandoc.Readers.Org ( readOrg ) where
2930
31+import Prelude
3032import Text.Pandoc.Readers.Org.Blocks (blockList, meta)
3133import Text.Pandoc.Readers.Org.ParserState (optionsToParserState)
3234import Text.Pandoc.Readers.Org.Parsing (OrgParser, readWithM)
src/Text/Pandoc/Readers/Org/BlockStarts.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -40,6 +41,7 @@ module Text.Pandoc.Readers.Org.BlockStarts
4041 , endOfBlock
4142 ) where
4243
44+import Prelude
4345import Control.Monad (void)
4446import Text.Pandoc.Readers.Org.Parsing
4547
src/Text/Pandoc/Readers/Org/Blocks.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -31,6 +32,7 @@ module Text.Pandoc.Readers.Org.Blocks
3132 , meta
3233 ) where
3334
35+import Prelude
3436import Text.Pandoc.Readers.Org.BlockStarts
3537import Text.Pandoc.Readers.Org.DocumentTree (documentTree, headlineToBlocks)
3638import Text.Pandoc.Readers.Org.Inlines
@@ -51,7 +53,6 @@ import Data.Char (isSpace, toLower, toUpper)
5153import Data.Default (Default)
5254import Data.List (foldl', isPrefixOf)
5355import Data.Maybe (fromMaybe, isJust, isNothing)
54−import Data.Monoid ((<>))
5556
5657import qualified Text.Pandoc.Builder as B
5758import qualified Text.Pandoc.Walk as Walk
src/Text/Pandoc/Readers/Org/DocumentTree.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -32,11 +33,11 @@ module Text.Pandoc.Readers.Org.DocumentTree
3233 , headlineToBlocks
3334 ) where
3435
36+import Prelude
3537import Control.Arrow ((***))
3638import Control.Monad (guard, void)
3739import Data.Char (toLower, toUpper)
3840import Data.List (intersperse)
39−import Data.Monoid ((<>))
4041import Text.Pandoc.Builder (Blocks, Inlines)
4142import Text.Pandoc.Class (PandocMonad)
4243import Text.Pandoc.Definition
src/Text/Pandoc/Readers/Org/ExportSettings.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2016-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -29,6 +30,7 @@ module Text.Pandoc.Readers.Org.ExportSettings
2930 ( exportSettings
3031 ) where
3132
33+import Prelude
3234import Text.Pandoc.Readers.Org.ParserState
3335import Text.Pandoc.Readers.Org.Parsing
3436
src/Text/Pandoc/Readers/Org/Inlines.hs+2−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Inlines
3334 , linkTarget
3435 ) where
3536
37+import Prelude
3638import Text.Pandoc.Readers.Org.BlockStarts (endOfBlock, noteMarker)
3739import Text.Pandoc.Readers.Org.ParserState
3840import Text.Pandoc.Readers.Org.Parsing
@@ -55,9 +57,6 @@ import Data.Char (isAlphaNum, isSpace)
5557import Data.List (intersperse)
5658import qualified Data.Map as M
5759import Data.Maybe (fromMaybe)
58−import Data.Monoid ((<>))
59−import Data.Traversable (sequence)
60−import Prelude hiding (sequence)
6160
6261--
6362-- Functions acting on the parser state
src/Text/Pandoc/Readers/Org/Meta.hs+5−6
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE TupleSections #-}
34{-
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Meta
3334 , metaLine
3435 ) where
3536
37+import Prelude
3638import Text.Pandoc.Readers.Org.BlockStarts
3739import Text.Pandoc.Readers.Org.ExportSettings (exportSettings)
3840import Text.Pandoc.Readers.Org.Inlines
@@ -48,6 +50,7 @@ import Text.Pandoc.Shared (safeRead)
4850import Control.Monad (mzero, void, when)
4951import Data.Char (toLower)
5052import Data.List (intersperse)
53+import Data.Maybe (fromMaybe)
5154import qualified Data.Map as M
5255import Network.HTTP (urlEncode)
5356
@@ -189,16 +192,12 @@ parseFormat = try $ replacePlain <|> replaceUrl <|> justAppend
189192
190193setEmphasisPreChar :: Maybe [Char] -> OrgParserState -> OrgParserState
191194setEmphasisPreChar csMb st =
192− let preChars = case csMb of
193− Nothing -> orgStateEmphasisPreChars defaultOrgParserState
194− Just cs -> cs
195+ let preChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
195196 in st { orgStateEmphasisPreChars = preChars }
196197
197198setEmphasisPostChar :: Maybe [Char] -> OrgParserState -> OrgParserState
198199setEmphasisPostChar csMb st =
199− let postChars = case csMb of
200− Nothing -> orgStateEmphasisPostChars defaultOrgParserState
201− Just cs -> cs
200+ let postChars = fromMaybe (orgStateEmphasisPostChars defaultOrgParserState) csMb
202201 in st { orgStateEmphasisPostChars = postChars }
203202
204203emphChars :: Monad m => OrgParser m (Maybe [Char])
src/Text/Pandoc/Readers/Org/ParserState.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE MultiParamTypeClasses #-}
34{-
@@ -54,6 +55,7 @@ module Text.Pandoc.Readers.Org.ParserState
5455 , optionsToParserState
5556 ) where
5657
58+import Prelude
5759import Control.Monad.Reader (ReaderT, asks, local)
5860
5961import Data.Default (Default (..))
src/Text/Pandoc/Readers/Org/Parsing.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
34
@@ -112,6 +113,7 @@ module Text.Pandoc.Readers.Org.Parsing
112113 , getPosition
113114 ) where
114115
116+import Prelude
115117import Text.Pandoc.Readers.Org.ParserState
116118
117119import Text.Pandoc.Parsing hiding (F, anyLine, blanklines, newline,
src/Text/Pandoc/Readers/Org/Shared.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2014-2018 Albert Krewinkel <tarleb+pandoc@moltkeplatz.de>
@@ -33,6 +34,7 @@ module Text.Pandoc.Readers.Org.Shared
3334 , translateLang
3435 ) where
3536
37+import Prelude
3638import Data.Char (isAlphaNum)
3739import Data.List (isPrefixOf, isSuffixOf)
3840
src/Text/Pandoc/Readers/RST.hs+18−8
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3132Conversion from reStructuredText to 'Pandoc' document.
3233-}
3334module Text.Pandoc.Readers.RST ( readRST ) where
35+import Prelude
3436import Control.Arrow (second)
3537import Control.Monad (forM_, guard, liftM, mplus, mzero, when)
3638import Control.Monad.Except (throwError)
@@ -40,7 +42,6 @@ import Data.List (deleteFirstsBy, elemIndex, intercalate, isInfixOf, isSuffixOf,
4042 nub, sort, transpose, union)
4143import qualified Data.Map as M
4244import Data.Maybe (fromMaybe, isJust)
43−import Data.Monoid ((<>))
4445import Data.Sequence (ViewR (..), viewr)
4546import Data.Text (Text)
4647import qualified Data.Text as T
@@ -80,7 +81,7 @@ type RSTParser m = ParserT [Char] ParserState m
8081---
8182
8283bulletListMarkers :: [Char]
83−bulletListMarkers = "*+-"
84+bulletListMarkers = "*+-•‣⁃"
8485
8586underlineChars :: [Char]
8687underlineChars = "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~"
@@ -650,11 +651,15 @@ directive' = do
650651 skipMany spaceChar
651652 top <- many $ satisfy (/='\n')
652653 <|> try (char '\n' <*
653− notFollowedBy' (rawFieldListItem 3) <*
654− count 3 (char ' ') <*
654+ notFollowedBy' (rawFieldListItem 1) <*
655+ many1 (char ' ') <*
655656 notFollowedBy blankline)
656657 newline
657− fields <- many $ rawFieldListItem 3
658+ fields <- do
659+ fieldIndent <- length <$> lookAhead (many (char ' '))
660+ if fieldIndent == 0
661+ then return []
662+ else many $ rawFieldListItem fieldIndent
658663 body <- option "" $ try $ blanklines >> indentedBlock
659664 optional blanklines
660665 let body' = body ++ "\n\n"
@@ -1085,10 +1090,15 @@ targetURI :: Monad m => ParserT [Char] st m [Char]
10851090targetURI = do
10861091 skipSpaces
10871092 optional newline
1088− contents <- many1 (try (many spaceChar >> newline >>
1089− many1 spaceChar >> noneOf " \t\n") <|> noneOf "\n")
1093+ contents <- trim <$>
1094+ many1 (satisfy (/='\n')
1095+ <|> try (newline >> many1 spaceChar >> noneOf " \t\n"))
10901096 blanklines
1091− return $ escapeURI $ trim contents
1097+ case reverse contents of
1098+ -- strip backticks
1099+ '_':'`':xs -> return (dropWhile (=='`') (reverse xs) ++ "_")
1100+ '_':_ -> return contents
1101+ _ -> return (escapeURI contents)
10921102
10931103substKey :: PandocMonad m => RSTParser m ()
10941104substKey = try $ do
src/Text/Pandoc/Readers/TWiki.hs+5−4
@@ -1,7 +1,7 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE RelaxedPolyRec #-}
4−{-# LANGUAGE TypeSynonymInstances #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE RelaxedPolyRec #-}
4+
55-- RelaxedPolyRec needed for inlinesBetween on GHC < 7
66{-
77 Copyright (C) 2014 Alexander Sulfrian <alexander.sulfrian@fu-berlin.de>
@@ -35,6 +35,7 @@ Conversion of twiki text to 'Pandoc' document.
3535module Text.Pandoc.Readers.TWiki ( readTWiki
3636 ) where
3737
38+import Prelude
3839import Control.Monad
3940import Control.Monad.Except (throwError)
4041import Data.Char (isAlphaNum)
src/Text/Pandoc/Readers/Textile.hs+3−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2010-2012 Paul Rivier <paul*rivier#demotera*com> | tr '*#' '.@'
34 2010-2018 John MacFarlane
@@ -52,11 +53,11 @@ TODO : refactor common patterns across readers :
5253
5354
5455module Text.Pandoc.Readers.Textile ( readTextile) where
56+import Prelude
5557import Control.Monad (guard, liftM)
5658import Control.Monad.Except (throwError)
5759import Data.Char (digitToInt, isUpper)
5860import Data.List (intercalate, intersperse, transpose)
59−import Data.Monoid ((<>))
6061import Data.Text (Text)
6162import qualified Data.Text as T
6263import Text.HTML.TagSoup (Tag (..), fromAttrib)
@@ -394,7 +395,7 @@ table = try $ do
394395 (toprow:rest) | any (fst . fst) toprow ->
395396 (toprow, rest)
396397 _ -> (mempty, rawrows)
397− let nbOfCols = max (length headers) (length $ head rows)
398+ let nbOfCols = maximum $ map length (headers:rows)
398399 let aligns = map minimum $ transpose $ map (map (snd . fst)) (headers:rows)
399400 return $ B.table caption
400401 (zip aligns (replicate nbOfCols 0.0))
src/Text/Pandoc/Readers/TikiWiki.hs+6−6
@@ -1,13 +1,12 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE FlexibleInstances #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE RelaxedPolyRec #-}
5−{-# LANGUAGE TypeSynonymInstances #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RelaxedPolyRec #-}
65
76{- |
87 Module : Text.Pandoc.Readers.TikiWiki
98 Copyright : Copyright (C) 2017 Robin Lee Powell
10− License : GPLv2
9+ License : GNU GPL, version 2 or above
1110
1211 Maintainer : Robin Lee Powell <robinleepowell@gmail.com>
1312 Stability : alpha
@@ -19,6 +18,7 @@ Conversion of TikiWiki text to 'Pandoc' document.
1918module Text.Pandoc.Readers.TikiWiki ( readTikiWiki
2019 ) where
2120
21+import Prelude
2222import Control.Monad
2323import Control.Monad.Except (throwError)
2424import qualified Data.Foldable as F
src/Text/Pandoc/Readers/Txt2Tags.hs+4−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2014 Matthew Pickering <matthewtpickering@gmail.com>
34
@@ -31,6 +32,7 @@ module Text.Pandoc.Readers.Txt2Tags ( readTxt2Tags
3132 )
3233 where
3334
35+import Prelude
3436import Control.Monad (guard, void, when)
3537import Control.Monad.Except (catchError, throwError)
3638import Control.Monad.Reader (Reader, asks, runReader)
@@ -38,7 +40,6 @@ import Data.Char (toLower)
3840import Data.Default
3941import Data.List (intercalate, transpose)
4042import Data.Maybe (fromMaybe)
41−import Data.Monoid ((<>))
4243import Data.Text (Text)
4344import qualified Data.Text as T
4445import Data.Time.Format (formatTime)
@@ -46,7 +47,7 @@ import Text.Pandoc.Builder (Blocks, Inlines, trimInlines)
4647import qualified Text.Pandoc.Builder as B
4748import Text.Pandoc.Class (PandocMonad)
4849import qualified Text.Pandoc.Class as P
49−import Text.Pandoc.Compat.Time (defaultTimeLocale)
50+import Data.Time (defaultTimeLocale)
5051import Text.Pandoc.Definition
5152import Text.Pandoc.Options
5253import Text.Pandoc.Parsing hiding (space, spaces, uri)
@@ -444,7 +445,7 @@ inlineMarkup p f c special = try $ do
444445 let end' = case drop 2 end of
445446 "" -> mempty
446447 xs -> special xs
447− return $ f (start' <> body' <> end')
448+ return $ f (start' `mappend` body' `mappend` end')
448449 Nothing -> do -- Either bad or case such as *****
449450 guard (l >= 5)
450451 let body' = replicate (l - 4) c
src/Text/Pandoc/Readers/Vimwiki.hs+3−1
@@ -1,3 +1,5 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
13{-
24 Copyright (C) 2017-2018 Yuchen Pei <me@ypei.me>
35
@@ -63,12 +65,12 @@ Conversion of vimwiki text to 'Pandoc' document.
6365
6466module Text.Pandoc.Readers.Vimwiki ( readVimwiki
6567 ) where
68+import Prelude
6669import Control.Monad (guard)
6770import Control.Monad.Except (throwError)
6871import Data.Default
6972import Data.List (isInfixOf, isPrefixOf)
7073import Data.Maybe
71−import Data.Monoid ((<>))
7274import Data.Text (Text, unpack)
7375import Text.Pandoc.Builder (Blocks, Inlines, fromList, toList, trimInlines)
7476import qualified Text.Pandoc.Builder as B (blockQuote, bulletList, code,
src/Text/Pandoc/SelfContained.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2011-2018 John MacFarlane <jgm@berkeley.edu>
@@ -31,6 +32,7 @@ offline, by incorporating linked images, CSS, and scripts into
3132the HTML using data URIs.
3233-}
3334module Text.Pandoc.SelfContained ( makeDataURI, makeSelfContained ) where
35+import Prelude
3436import Codec.Compression.GZip as Gzip
3537import Control.Applicative ((<|>))
3638import Control.Monad.Except (throwError)
@@ -41,7 +43,6 @@ import qualified Data.ByteString.Char8 as B
4143import qualified Data.ByteString.Lazy as L
4244import Data.Char (isAlphaNum, isAscii, toLower)
4345import Data.List (isPrefixOf)
44−import Data.Monoid ((<>))
4546import Network.URI (escapeURIString)
4647import System.FilePath (takeDirectory, takeExtension, (</>))
4748import Text.HTML.TagSoup
src/Text/Pandoc/Shared.hs+20−10
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE DeriveDataTypeable #-}
34{-# LANGUAGE FlexibleContexts #-}
@@ -83,6 +84,7 @@ module Text.Pandoc.Shared (
8384 -- * File handling
8485 inDirectory,
8586 collapseFilePath,
87+ uriPathToPath,
8688 filteredFilesFromArchive,
8789 -- * URI handling
8890 schemes,
@@ -100,6 +102,7 @@ module Text.Pandoc.Shared (
100102 pandocVersion
101103 ) where
102104
105+import Prelude
103106import Codec.Archive.Zip
104107import qualified Control.Exception as E
105108import Control.Monad (MonadPlus (..), msum, unless)
@@ -111,7 +114,6 @@ import Data.Data (Data, Typeable)
111114import Data.List (find, intercalate, intersperse, stripPrefix)
112115import qualified Data.Map as M
113116import Data.Maybe (mapMaybe)
114−import Data.Monoid ((<>))
115117import Data.Sequence (ViewL (..), ViewR (..), viewl, viewr)
116118import qualified Data.Set as Set
117119import qualified Data.Text as T
@@ -126,7 +128,7 @@ import Text.HTML.TagSoup (RenderOptions (..), Tag (..), renderOptions,
126128 renderTagsOptions)
127129import Text.Pandoc.Builder (Blocks, Inlines, ToMetaValue (..))
128130import qualified Text.Pandoc.Builder as B
129−import Text.Pandoc.Compat.Time
131+import Data.Time
130132import Text.Pandoc.Definition
131133import Text.Pandoc.Generic (bottomUp)
132134import Text.Pandoc.Pretty (charWidth)
@@ -286,12 +288,7 @@ normalizeDate s = fmap (formatTime defaultTimeLocale "%F")
286288 where rejectBadYear day = case toGregorian day of
287289 (y, _, _) | y >= 1601 && y <= 9999 -> Just day
288290 _ -> Nothing
289− parsetimeWith =
290−#if MIN_VERSION_time(1,5,0)
291− parseTimeM True defaultTimeLocale
292−#else
293− parseTime defaultTimeLocale
294−#endif
291+ parsetimeWith = parseTimeM True defaultTimeLocale
295292 formats = ["%x","%m/%d/%Y", "%D","%F", "%d %b %Y",
296293 "%e %B %Y", "%b. %e, %Y", "%B %e, %Y",
297294 "%Y%m%d", "%Y%m", "%Y"]
@@ -447,7 +444,7 @@ instance Walkable Inline Element where
447444 elts' <- walkM f elts
448445 return $ Sec lev nums attr ils' elts'
449446 query f (Blk x) = query f x
450− query f (Sec _ _ _ ils elts) = query f ils <> query f elts
447+ query f (Sec _ _ _ ils elts) = query f ils `mappend` query f elts
451448
452449instance Walkable Block Element where
453450 walk f (Blk x) = Blk (walk f x)
@@ -458,7 +455,7 @@ instance Walkable Block Element where
458455 elts' <- walkM f elts
459456 return $ Sec lev nums attr ils' elts'
460457 query f (Blk x) = query f x
461− query f (Sec _ _ _ ils elts) = query f ils <> query f elts
458+ query f (Sec _ _ _ ils elts) = query f ils `mappend` query f elts
462459
463460
464461-- | Convert Pandoc inline list to plain text identifier. HTML
@@ -639,6 +636,19 @@ collapseFilePath = Posix.joinPath . reverse . foldl go [] . splitDirectories
639636 isSingleton _ = Nothing
640637 checkPathSeperator = fmap isPathSeparator . isSingleton
641638
639+-- Convert the path part of a file: URI to a regular path.
640+-- On windows, @/c:/foo@ should be @c:/foo@.
641+-- On linux, @/foo@ should be @/foo@.
642+uriPathToPath :: String -> FilePath
643+uriPathToPath path =
644+#ifdef _WINDOWS
645+ case path of
646+ '/':ps -> ps
647+ ps -> ps
648+#else
649+ path
650+#endif
651+
642652--
643653-- File selection from the archive
644654--
src/Text/Pandoc/Slides.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -29,6 +30,7 @@ Utility functions for splitting documents into slides for slide
2930show formats (dzslides, revealjs, s5, slidy, slideous, beamer).
3031-}
3132module Text.Pandoc.Slides ( getSlideLevel, prepSlides ) where
33+import Prelude
3234import Text.Pandoc.Definition
3335
3436-- | Find level of header that starts slides (defined as the least header
src/Text/Pandoc/Templates.hs+2−4
@@ -1,7 +1,4 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE TypeSynonymInstances #-}
1+{-# LANGUAGE OverloadedStrings #-}
52{-
63Copyright (C) 2009-2018 John MacFarlane <jgm@berkeley.edu>
74
@@ -38,6 +35,7 @@ module Text.Pandoc.Templates ( module Text.DocTemplates
3835 , getDefaultTemplate
3936 ) where
4037
38+import Prelude
4139import Control.Monad.Except (throwError)
4240import Data.Aeson (ToJSON (..))
4341import qualified Data.Text as T
src/Text/Pandoc/Translations.hs+4−1
@@ -1,3 +1,5 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE CPP #-}
13{-# LANGUAGE DeriveGeneric #-}
24{-# LANGUAGE GeneralizedNewtypeDeriving #-}
35{-
@@ -45,6 +47,7 @@ module Text.Pandoc.Translations (
4547 , readTranslations
4648 )
4749where
50+import Prelude
4851import Data.Aeson.Types (typeMismatch)
4952import qualified Data.HashMap.Strict as HM
5053import qualified Data.Map as M
@@ -80,7 +83,7 @@ data Term =
8083 deriving (Show, Eq, Ord, Generic, Enum, Read)
8184
8285newtype Translations = Translations (M.Map Term String)
83− deriving (Show, Generic, Monoid)
86+ deriving (Show, Generic, Semigroup, Monoid)
8487
8588instance FromJSON Term where
8689 parseJSON (String t) = case safeRead (T.unpack t) of
src/Text/Pandoc/UTF8.hs+1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
src/Text/Pandoc/UUID.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -31,6 +32,7 @@ in RFC4122. See http://tools.ietf.org/html/rfc4122
3132
3233module Text.Pandoc.UUID ( UUID(..), getRandomUUID, getUUID ) where
3334
35+import Prelude
3436import Data.Bits (clearBit, setBit)
3537import Data.Word
3638import System.Random (RandomGen, getStdGen, randoms)
src/Text/Pandoc/Writers.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -82,6 +83,7 @@ module Text.Pandoc.Writers
8283 , getWriter
8384 ) where
8485
86+import Prelude
8587import Data.Aeson
8688import qualified Data.ByteString.Lazy as BL
8789import Data.List (intercalate)
src/Text/Pandoc/Writers/AsciiDoc.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -37,6 +38,7 @@ that it has omitted the construct.
3738AsciiDoc: <http://www.methods.co.nz/asciidoc/>
3839-}
3940module Text.Pandoc.Writers.AsciiDoc (writeAsciiDoc) where
41+import Prelude
4042import Control.Monad.State.Strict
4143import Data.Aeson (Result (..), Value (String), fromJSON, toJSON)
4244import Data.Char (isPunctuation, isSpace)
src/Text/Pandoc/Writers/CommonMark.hs+4−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2015-2018 John MacFarlane <jgm@berkeley.edu>
@@ -32,11 +33,12 @@ CommonMark: <http://commonmark.org>
3233-}
3334module Text.Pandoc.Writers.CommonMark (writeCommonMark) where
3435
36+import Prelude
3537import CMarkGFM
3638import Control.Monad.State.Strict (State, get, modify, runState)
3739import Data.Foldable (foldrM)
3840import Data.List (transpose)
39−import Data.Monoid (Any (..), (<>))
41+import Data.Monoid (Any (..))
4042import Data.Text (Text)
4143import qualified Data.Text as T
4244import Network.HTTP (urlEncode)
@@ -114,7 +116,7 @@ blockToNodes _ (CodeBlock (_,classes,_) xs) ns = return
114116blockToNodes opts (RawBlock fmt xs) ns
115117 | fmt == Format "html" && isEnabled Ext_raw_html opts
116118 = return (node (HTML_BLOCK (T.pack xs)) [] : ns)
117− | fmt == Format "latex" || fmt == Format "tex" && isEnabled Ext_raw_tex opts
119+ | (fmt == Format "latex" || fmt == Format "tex") && isEnabled Ext_raw_tex opts
118120 = return (node (CUSTOM_BLOCK (T.pack xs) T.empty) [] : ns)
119121 | otherwise = return ns
120122blockToNodes opts (BlockQuote bs) ns = do
src/Text/Pandoc/Writers/ConTeXt.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE ScopedTypeVariables #-}
34{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3031Conversion of 'Pandoc' format into ConTeXt.
3132-}
3233module Text.Pandoc.Writers.ConTeXt ( writeConTeXt ) where
34+import Prelude
3335import Control.Monad.State.Strict
3436import Data.Char (ord, isDigit)
3537import Data.List (intercalate, intersperse)
src/Text/Pandoc/Writers/Custom.hs+4−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE DeriveDataTypeable #-}
23{-# LANGUAGE FlexibleInstances #-}
34{- Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to custom markup using
3031a lua writer.
3132-}
3233module Text.Pandoc.Writers.Custom ( writeCustom ) where
34+import Prelude
3335import Control.Arrow ((***))
3436import Control.Exception
3537import Control.Monad (when)
@@ -44,7 +46,7 @@ import Foreign.Lua.Api
4446import Text.Pandoc.Class (PandocIO)
4547import Text.Pandoc.Definition
4648import Text.Pandoc.Error
47−import Text.Pandoc.Lua.Init (runPandocLua)
49+import Text.Pandoc.Lua.Init (runPandocLua, registerScriptPath)
4850import Text.Pandoc.Lua.StackInstances ()
4951import Text.Pandoc.Lua.Util (addValue, dostring')
5052import Text.Pandoc.Options
@@ -106,6 +108,7 @@ writeCustom :: FilePath -> WriterOptions -> Pandoc -> PandocIO Text
106108writeCustom luaFile opts doc@(Pandoc meta _) = do
107109 luaScript <- liftIO $ UTF8.readFile luaFile
108110 res <- runPandocLua $ do
111+ registerScriptPath luaFile
109112 stat <- dostring' luaScript
110113 -- check for error in lua script (later we'll change the return type
111114 -- to handle this more gracefully):
src/Text/Pandoc/Writers/Docbook.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE PatternGuards #-}
34{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3031Conversion of 'Pandoc' documents to Docbook XML.
3132-}
3233module Text.Pandoc.Writers.Docbook ( writeDocbook4, writeDocbook5 ) where
34+import Prelude
3335import Control.Monad.Reader
3436import Data.Char (toLower)
3537import Data.Generics (everywhere, mkT)
src/Text/Pandoc/Writers/Docx.hs+113−92
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE PatternGuards #-}
23{-# LANGUAGE RankNTypes #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3233Conversion of 'Pandoc' documents to docx.
3334-}
3435module Text.Pandoc.Writers.Docx ( writeDocx ) where
36+import Prelude
3537import Codec.Archive.Zip
3638import Control.Applicative ((<|>))
3739import Control.Monad.Except (catchError)
@@ -51,7 +53,7 @@ import System.Random (randomR, StdGen, mkStdGen)
5153import Text.Pandoc.BCP47 (getLang, renderLang)
5254import Text.Pandoc.Class (PandocMonad, report, toLang)
5355import qualified Text.Pandoc.Class as P
54−import Text.Pandoc.Compat.Time
56+import Data.Time
5557import Text.Pandoc.Definition
5658import Text.Pandoc.Generic
5759import Text.Pandoc.Highlighting (highlight)
@@ -123,7 +125,7 @@ data WriterState = WriterState{
123125 , stComments :: [([(String,String)], [Inline])]
124126 , stSectionIds :: Set.Set String
125127 , stExternalLinks :: M.Map String String
126− , stImages :: M.Map FilePath (String, String, Maybe MimeType, Element, B.ByteString)
128+ , stImages :: M.Map FilePath (String, String, Maybe MimeType, B.ByteString)
127129 , stLists :: [ListMarker]
128130 , stInsId :: Int
129131 , stDelId :: Int
@@ -294,7 +296,7 @@ writeDocx opts doc@(Pandoc meta _) = do
294296 let imgs = M.elems $ stImages st
295297
296298 -- create entries for images in word/media/...
297− let toImageEntry (_,path,_,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
299+ let toImageEntry (_,path,_,img) = toEntry ("word/" ++ path) epochtime $ toLazy img
298300 let imageEntries = map toImageEntry imgs
299301
300302 let stdAttributes =
@@ -326,7 +328,7 @@ writeDocx opts doc@(Pandoc meta _) = do
326328 -- [Content_Types].xml
327329 let mkOverrideNode (part', contentType') = mknode "Override"
328330 [("PartName",part'),("ContentType",contentType')] ()
329− let mkImageOverride (_, imgpath, mbMimeType, _, _) =
331+ let mkImageOverride (_, imgpath, mbMimeType, _) =
330332 mkOverrideNode ("/word/" ++ imgpath,
331333 fromMaybe "application/octet-stream" mbMimeType)
332334 let mkMediaOverride imgpath =
@@ -407,7 +409,7 @@ writeDocx opts doc@(Pandoc meta _) = do
407409 let renumHeaders = renumIds (\q -> qName q == "Id") idMap headers
408410 let renumFooters = renumIds (\q -> qName q == "Id") idMap footers
409411 let baserels = baserels' ++ renumHeaders ++ renumFooters
410− let toImgRel (ident,path,_,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
412+ let toImgRel (ident,path,_,_) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"),("Id",ident),("Target",path)] ()
411413 let imgrels = map toImgRel imgs
412414 let toLinkRel (src,ident) = mknode "Relationship" [("Type","http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"),("Id",ident),("Target",src),("TargetMode","External") ] ()
413415 let linkrels = map toLinkRel $ M.toList $ stExternalLinks st
@@ -708,12 +710,12 @@ mkLvl marker lvl =
708710 styleFor UpperRoman _ = "upperRoman"
709711 styleFor LowerRoman _ = "lowerRoman"
710712 styleFor Decimal _ = "decimal"
711− styleFor DefaultStyle 1 = "decimal"
712− styleFor DefaultStyle 2 = "lowerLetter"
713− styleFor DefaultStyle 3 = "lowerRoman"
714− styleFor DefaultStyle 4 = "decimal"
715− styleFor DefaultStyle 5 = "lowerLetter"
716− styleFor DefaultStyle 0 = "lowerRoman"
713+ styleFor DefaultStyle 0 = "decimal"
714+ styleFor DefaultStyle 1 = "lowerLetter"
715+ styleFor DefaultStyle 2 = "lowerRoman"
716+ styleFor DefaultStyle 3 = "decimal"
717+ styleFor DefaultStyle 4 = "lowerLetter"
718+ styleFor DefaultStyle 5 = "lowerRoman"
717719 styleFor DefaultStyle x = styleFor DefaultStyle (x `mod` 6)
718720 styleFor _ _ = "decimal"
719721 patternFor OneParen s = s ++ ")"
@@ -1109,6 +1111,9 @@ inlineToOpenXML' _ (Str str) =
11091111 formattedString str
11101112inlineToOpenXML' opts Space = inlineToOpenXML opts (Str " ")
11111113inlineToOpenXML' opts SoftBreak = inlineToOpenXML opts (Str " ")
1114+inlineToOpenXML' opts (Span (_,["underline"],_) ils) = do
1115+ withTextProp (mknode "w:u" [("w:val","single")] ()) $
1116+ inlinesToOpenXML opts ils
11121117inlineToOpenXML' _ (Span (ident,["comment-start"],kvs) ils) = do
11131118 -- prefer the "id" in kvs, since that is the one produced by the docx
11141119 -- reader.
@@ -1275,87 +1280,103 @@ inlineToOpenXML' opts (Link _ txt (src,_)) = do
12751280 return i
12761281 return [ mknode "w:hyperlink" [("r:id",id')] contents ]
12771282inlineToOpenXML' opts (Image attr alt (src, title)) = do
1278− -- first, check to see if we've already done this image
12791283 pageWidth <- asks envPrintWidth
12801284 imgs <- gets stImages
1281− case M.lookup src imgs of
1282− Just (_,_,_,elt,_) -> return [elt]
1283− Nothing ->
1284− catchError
1285− (do (img, mt) <- P.fetchItem src
1286− ident <- ("rId"++) `fmap` getUniqueId
1287− let (xpt,ypt) = desiredSizeInPoints opts attr
1288− (either (const def) id (imageSize opts img))
1289− -- 12700 emu = 1 pt
1290− let (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
1291− (pageWidth * 12700)
1292− let cNvPicPr = mknode "pic:cNvPicPr" [] $
1293− mknode "a:picLocks" [("noChangeArrowheads","1")
1294− ,("noChangeAspect","1")] ()
1295− let nvPicPr = mknode "pic:nvPicPr" []
1296− [ mknode "pic:cNvPr"
1297− [("descr",src),("id","0"),("name","Picture")] ()
1298− , cNvPicPr ]
1299− let blipFill = mknode "pic:blipFill" []
1300− [ mknode "a:blip" [("r:embed",ident)] ()
1301− , mknode "a:stretch" [] $
1302− mknode "a:fillRect" [] () ]
1303− let xfrm = mknode "a:xfrm" []
1304− [ mknode "a:off" [("x","0"),("y","0")] ()
1305− , mknode "a:ext" [("cx",show xemu)
1306− ,("cy",show yemu)] () ]
1307− let prstGeom = mknode "a:prstGeom" [("prst","rect")] $
1308− mknode "a:avLst" [] ()
1309− let ln = mknode "a:ln" [("w","9525")]
1310− [ mknode "a:noFill" [] ()
1311− , mknode "a:headEnd" [] ()
1312− , mknode "a:tailEnd" [] () ]
1313− let spPr = mknode "pic:spPr" [("bwMode","auto")]
1314− [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
1315− let graphic = mknode "a:graphic" [] $
1316− mknode "a:graphicData"
1317− [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
1318− [ mknode "pic:pic" []
1319− [ nvPicPr
1320− , blipFill
1321− , spPr ] ]
1322− let imgElt = mknode "w:r" [] $
1323− mknode "w:drawing" [] $
1324− mknode "wp:inline" []
1325− [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
1326− , mknode "wp:effectExtent"
1327− [("b","0"),("l","0"),("r","0"),("t","0")] ()
1328− , mknode "wp:docPr" [("descr",stringify alt)
1329− ,("title", title)
1330− ,("id","1")
1331− ,("name","Picture")] ()
1332− , graphic ]
1333− let imgext = case mt >>= extensionFromMimeType of
1334− Just x -> '.':x
1335− Nothing -> case imageType img of
1336− Just Png -> ".png"
1337− Just Jpeg -> ".jpeg"
1338− Just Gif -> ".gif"
1339− Just Pdf -> ".pdf"
1340− Just Eps -> ".eps"
1341− Just Svg -> ".svg"
1342− Just Emf -> ".emf"
1343− Nothing -> ""
1344− if null imgext
1345− then -- without an extension there is no rule for content type
1346− inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
1347− else do
1348− let imgpath = "media/" ++ ident ++ imgext
1349− let mbMimeType = mt <|> getMimeType imgpath
1350− -- insert mime type to use in constructing [Content_Types].xml
1351− modify $ \st -> st{ stImages =
1352− M.insert src (ident, imgpath, mbMimeType, imgElt, img)
1353− $ stImages st }
1354− return [imgElt])
1355− (\e -> do
1356− report $ CouldNotFetchResource src (show e)
1357− -- emit alt text
1358− inlinesToOpenXML opts alt)
1285+ let
1286+ stImage = M.lookup src imgs
1287+ generateImgElt (ident, _, _, img) =
1288+ let
1289+ (xpt,ypt) = desiredSizeInPoints opts attr
1290+ (either (const def) id (imageSize opts img))
1291+ -- 12700 emu = 1 pt
1292+ (xemu,yemu) = fitToPage (xpt * 12700, ypt * 12700)
1293+ (pageWidth * 12700)
1294+ cNvPicPr = mknode "pic:cNvPicPr" [] $
1295+ mknode "a:picLocks" [("noChangeArrowheads","1")
1296+ ,("noChangeAspect","1")] ()
1297+ nvPicPr = mknode "pic:nvPicPr" []
1298+ [ mknode "pic:cNvPr"
1299+ [("descr",src),("id","0"),("name","Picture")] ()
1300+ , cNvPicPr ]
1301+ blipFill = mknode "pic:blipFill" []
1302+ [ mknode "a:blip" [("r:embed",ident)] ()
1303+ , mknode "a:stretch" [] $
1304+ mknode "a:fillRect" [] ()
1305+ ]
1306+ xfrm = mknode "a:xfrm" []
1307+ [ mknode "a:off" [("x","0"),("y","0")] ()
1308+ , mknode "a:ext" [("cx",show xemu)
1309+ ,("cy",show yemu)] () ]
1310+ prstGeom = mknode "a:prstGeom" [("prst","rect")] $
1311+ mknode "a:avLst" [] ()
1312+ ln = mknode "a:ln" [("w","9525")]
1313+ [ mknode "a:noFill" [] ()
1314+ , mknode "a:headEnd" [] ()
1315+ , mknode "a:tailEnd" [] () ]
1316+ spPr = mknode "pic:spPr" [("bwMode","auto")]
1317+ [xfrm, prstGeom, mknode "a:noFill" [] (), ln]
1318+ graphic = mknode "a:graphic" [] $
1319+ mknode "a:graphicData"
1320+ [("uri","http://schemas.openxmlformats.org/drawingml/2006/picture")]
1321+ [ mknode "pic:pic" []
1322+ [ nvPicPr
1323+ , blipFill
1324+ , spPr
1325+ ]
1326+ ]
1327+ imgElt = mknode "w:r" [] $
1328+ mknode "w:drawing" [] $
1329+ mknode "wp:inline" []
1330+ [ mknode "wp:extent" [("cx",show xemu),("cy",show yemu)] ()
1331+ , mknode "wp:effectExtent"
1332+ [("b","0"),("l","0"),("r","0"),("t","0")] ()
1333+ , mknode "wp:docPr"
1334+ [ ("descr", stringify alt)
1335+ , ("title", title)
1336+ , ("id","1")
1337+ , ("name","Picture")
1338+ ] ()
1339+ , graphic
1340+ ]
1341+ in
1342+ imgElt
1343+
1344+ case stImage of
1345+ Just imgData -> return [generateImgElt imgData]
1346+ Nothing -> ( do --try
1347+ (img, mt) <- P.fetchItem src
1348+ ident <- ("rId"++) `fmap` getUniqueId
1349+
1350+ let
1351+ imgext = case mt >>= extensionFromMimeType of
1352+ Just x -> '.':x
1353+ Nothing -> case imageType img of
1354+ Just Png -> ".png"
1355+ Just Jpeg -> ".jpeg"
1356+ Just Gif -> ".gif"
1357+ Just Pdf -> ".pdf"
1358+ Just Eps -> ".eps"
1359+ Just Svg -> ".svg"
1360+ Just Emf -> ".emf"
1361+ Nothing -> ""
1362+ imgpath = "media/" ++ ident ++ imgext
1363+ mbMimeType = mt <|> getMimeType imgpath
1364+
1365+ imgData = (ident, imgpath, mbMimeType, img)
1366+
1367+ if null imgext
1368+ then -- without an extension there is no rule for content type
1369+ inlinesToOpenXML opts alt -- return alt to avoid corrupted docx
1370+ else do
1371+ -- insert mime type to use in constructing [Content_Types].xml
1372+ modify $ \st -> st { stImages = M.insert src imgData $ stImages st }
1373+ return [generateImgElt imgData]
1374+ )
1375+ `catchError` ( \e -> do
1376+ report $ CouldNotFetchResource src (show e)
1377+ -- emit alt text
1378+ inlinesToOpenXML opts alt
1379+ )
13591380
13601381br :: Element
13611382br = breakElement "textWrapping"
@@ -1370,12 +1391,12 @@ breakElement kind = mknode "w:r" [] [mknode "w:br" [("w:type",kind)] () ]
13701391defaultFootnotes :: [Element]
13711392defaultFootnotes = [ mknode "w:footnote"
13721393 [("w:type", "separator"), ("w:id", "-1")]
1373− [ mknode "w:p" [] $
1394+ [ mknode "w:p" []
13741395 [mknode "w:r" [] $
13751396 [ mknode "w:separator" [] ()]]]
13761397 , mknode "w:footnote"
13771398 [("w:type", "continuationSeparator"), ("w:id", "0")]
1378− [ mknode "w:p" [] $
1399+ [ mknode "w:p" []
13791400 [ mknode "w:r" [] $
13801401 [ mknode "w:continuationSeparator" [] ()]]]]
13811402
src/Text/Pandoc/Writers/DokuWiki.hs+18−8
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -39,6 +40,7 @@ DokuWiki: <https://www.dokuwiki.org/dokuwiki>
3940-}
4041
4142module Text.Pandoc.Writers.DokuWiki ( writeDokuWiki ) where
43+import Prelude
4244import Control.Monad (zipWithM)
4345import Control.Monad.Reader (ReaderT, ask, local, runReaderT)
4446import Control.Monad.State.Strict (StateT, evalStateT)
@@ -366,12 +368,16 @@ isSimpleBlockQuote bs = all isPlainOrPara bs
366368vcat :: [String] -> String
367369vcat = intercalate "\n"
368370
369−backSlashLineBreaks :: String -> String
370−backSlashLineBreaks cs = reverse $ g $ reverse $ concatMap f cs
371− where f '\n' = "\\\\ "
372− f c = [c]
373− g (' ' : '\\':'\\': xs) = xs
374− g s = s
371+-- | For each string in the input list, convert all newlines to
372+-- dokuwiki escaped newlines. Then concat the list using double linebreaks.
373+backSlashLineBreaks :: [String] -> String
374+backSlashLineBreaks ls = vcatBackSlash $ map escape ls
375+ where
376+ vcatBackSlash = intercalate "\\\\ \\\\ " -- simulate paragraphs.
377+ escape ['\n'] = "" -- remove trailing newlines
378+ escape ('\n':cs) = "\\\\ " ++ escape cs
379+ escape (c:cs) = c : escape cs
380+ escape [] = []
375381
376382-- Auxiliary functions for tables:
377383
@@ -400,7 +406,7 @@ blockListToDokuWiki opts blocks = do
400406 backSlash <- stBackSlashLB <$> ask
401407 let blocks' = consolidateRawBlocks blocks
402408 if backSlash
403− then (backSlashLineBreaks . vcat) <$> mapM (blockToDokuWiki opts) blocks'
409+ then backSlashLineBreaks <$> mapM (blockToDokuWiki opts) blocks'
404410 else vcat <$> mapM (blockToDokuWiki opts) blocks'
405411
406412consolidateRawBlocks :: [Block] -> [Block]
@@ -479,7 +485,11 @@ inlineToDokuWiki _ il@(RawInline f str)
479485 | f == Format "html" = return $ "<html>" ++ str ++ "</html>"
480486 | otherwise = "" <$ report (InlineNotRendered il)
481487
482−inlineToDokuWiki _ LineBreak = return "\\\\\n"
488+inlineToDokuWiki _ LineBreak = do
489+ backSlash <- stBackSlashLB <$> ask
490+ return $ if backSlash
491+ then "\n"
492+ else "\\\\\n"
483493
484494inlineToDokuWiki opts SoftBreak =
485495 case writerWrapText opts of
src/Text/Pandoc/Writers/EPUB.hs+22−13
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE FlexibleContexts #-}
34{-# LANGUAGE PatternGuards #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3233Conversion of 'Pandoc' documents to EPUB.
3334-}
3435module Text.Pandoc.Writers.EPUB ( writeEPUB2, writeEPUB3 ) where
36+import Prelude
3537import Codec.Archive.Zip (Entry, addEntryToArchive, eRelativePath, emptyArchive,
3638 fromArchive, fromEntry, toEntry)
3739import Control.Monad (mplus, unless, when, zipWithM)
@@ -53,7 +55,7 @@ import Text.HTML.TagSoup (Tag (TagOpen), fromAttrib, parseTags)
5355import Text.Pandoc.Builder (fromList, setMeta)
5456import Text.Pandoc.Class (PandocMonad, report)
5557import qualified Text.Pandoc.Class as P
56−import Text.Pandoc.Compat.Time
58+import Data.Time
5759import Text.Pandoc.Definition
5860import Text.Pandoc.Error
5961import Text.Pandoc.Logging
@@ -401,6 +403,12 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
401403 writeHtmlStringForEPUB version o
402404 metadata <- getEPUBMetadata opts meta
403405
406+ let plainTitle = case docTitle' meta of
407+ [] -> case epubTitle metadata of
408+ [] -> "UNTITLED"
409+ (x:_) -> titleText x
410+ x -> stringify x
411+
404412 -- stylesheet
405413 stylesheets <- case epubStylesheets metadata of
406414 [] -> (\x -> [B.fromChunks [x]]) <$>
@@ -438,6 +446,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
438446 cpContent <- lift $ writeHtml
439447 opts'{ writerVariables =
440448 ("coverpage","true"):
449+ ("pagetitle",plainTitle):
441450 cssvars True ++ vars }
442451 (Pandoc meta [RawBlock (Format "html") $ "<div id=\"cover-image\">\n<img src=\"../media/" ++ coverImage ++ "\" alt=\"cover image\" />\n</div>"])
443452 imgContent <- lift $ P.readFileLazy img
@@ -450,6 +459,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
450459 -- title page
451460 tpContent <- lift $ writeHtml opts'{
452461 writerVariables = ("titlepage","true"):
462+ ("pagetitle",plainTitle):
453463 cssvars True ++ vars }
454464 (Pandoc meta [])
455465 tpEntry <- mkEntry "text/title_page.xhtml" tpContent
@@ -458,7 +468,7 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
458468 -- mediaRef <- P.newIORef []
459469 Pandoc _ blocks <- walkM (transformInline opts') doc >>=
460470 walkM transformBlock
461− picEntries <- (mapMaybe (snd . snd)) <$> gets stMediaPaths
471+ picEntries <- mapMaybe (snd . snd) <$> gets stMediaPaths
462472 -- handle fonts
463473 let matchingGlob f = do
464474 xs <- lift $ P.glob f
@@ -602,11 +612,6 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
602612 $ eRelativePath ent),
603613 ("media-type", fromMaybe "" $
604614 getMimeType $ eRelativePath ent)] $ ()
605− let plainTitle = case docTitle' meta of
606− [] -> case epubTitle metadata of
607− [] -> "UNTITLED"
608− (x:_) -> titleText x
609− x -> stringify x
610615
611616 let tocTitle = fromMaybe plainTitle $
612617 metaValueToString <$> lookupMeta "toc-title" meta
@@ -747,14 +752,18 @@ pandocToEPUB version opts doc@(Pandoc meta _) = do
747752 where titElements = parseXML titRendered
748753 titRendered = case P.runPure
749754 (writeHtmlStringForEPUB version
750− opts{ writerTemplate = Nothing }
755+ opts{ writerTemplate = Nothing
756+ , writerVariables =
757+ ("pagetitle",plainTitle):
758+ writerVariables opts}
751759 (Pandoc nullMeta
752− [Plain $ walk delink tit])) of
760+ [Plain $ walk clean tit])) of
753761 Left _ -> TS.pack $ stringify tit
754762 Right x -> x
755− -- can't have a element inside a...
756− delink (Link _ ils _) = Span ("", [], []) ils
757− delink x = x
763+ -- can't have <a> elements inside generated links...
764+ clean (Link _ ils _) = Span ("", [], []) ils
765+ clean (Note _) = Str ""
766+ clean x = x
758767
759768 let navtag = if epub3 then "nav" else "div"
760769 tocBlocks <- lift $ evalStateT (mapM (navPointNode navXhtmlFormatter) secs) 1
@@ -872,7 +881,7 @@ metadataElement version md currentTime =
872881 dcTag' n s = [dcTag n s]
873882 toIdentifierNode id' (Identifier txt scheme)
874883 | version == EPUB2 = [dcNode "identifier" !
875− ([("id",id')] ++ maybe [] (\x -> [("opf:scheme", x)]) scheme) $
884+ (("id",id') : maybe [] (\x -> [("opf:scheme", x)]) scheme) $
876885 txt]
877886 | otherwise = [dcNode "identifier" ! [("id",id')] $ txt] ++
878887 maybe [] (\x -> [unode "meta" !
src/Text/Pandoc/Writers/FB2.hs+16−33
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE PatternGuards #-}
23
34{-
@@ -37,6 +38,7 @@ FictionBook is an XML-based e-book format. For more information see:
3738-}
3839module Text.Pandoc.Writers.FB2 (writeFB2) where
3940
41+import Prelude
4042import Control.Monad (zipWithM)
4143import Control.Monad.Except (catchError)
4244import Control.Monad.State.Strict (StateT, evalStateT, get, lift, liftM, modify)
@@ -44,7 +46,7 @@ import Data.ByteString.Base64 (encode)
4446import qualified Data.ByteString.Char8 as B8
4547import Data.Char (isAscii, isControl, isSpace, toLower)
4648import Data.Either (lefts, rights)
47−import Data.List (intercalate, intersperse, isPrefixOf, stripPrefix)
49+import Data.List (intercalate, isPrefixOf, stripPrefix)
4850import Data.Text (Text, pack)
4951import Network.HTTP (urlEncode)
5052import Text.XML.Light
@@ -116,6 +118,9 @@ description meta' = do
116118 bt <- booktitle meta'
117119 let as = authors meta'
118120 dd <- docdate meta'
121+ annotation <- case lookupMeta "abstract" meta' of
122+ Just (MetaBlocks bs) -> (list . el "annotation") <$> cMapM blockToXml bs
123+ _ -> pure mempty
119124 let lang = case lookupMeta "lang" meta' of
120125 Just (MetaInlines [Str s]) -> [el "lang" $ iso639 s]
121126 Just (MetaString s) -> [el "lang" $ iso639 s]
@@ -130,7 +135,7 @@ description meta' = do
130135 Just (MetaString s) -> coverimage s
131136 _ -> return []
132137 return $ el "description"
133− [ el "title-info" (genre : (bt ++ as ++ dd ++ lang))
138+ [ el "title-info" (genre : (bt ++ annotation ++ as ++ dd ++ lang))
134139 , el "document-info" (el "program-used" "pandoc" : coverpage)
135140 ]
136141
@@ -178,7 +183,7 @@ renderSection :: PandocMonad m => Int -> ([Inline], [Block]) -> FBM m Content
178183renderSection level (ttl, body) = do
179184 title <- if null ttl
180185 then return []
181− else return . list . el "title" . formatTitle $ ttl
186+ else list . el "title" <$> formatTitle ttl
182187 content <- if hasSubsections body
183188 then renderSections (level + 1) body
184189 else cMapM blockToXml body
@@ -187,11 +192,9 @@ renderSection level (ttl, body) = do
187192 hasSubsections = any isHeaderBlock
188193
189194-- | Only <p> and <empty-line> are allowed within <title> in FB2.
190−formatTitle :: [Inline] -> [Content]
195+formatTitle :: PandocMonad m => [Inline] -> FBM m [Content]
191196formatTitle inlines =
192− let lns = split isLineBreak inlines
193− lns' = map (el "p" . cMap plain) lns
194− in intersperse (el "empty-line" ()) lns'
197+ cMapM (blockToXml . Para) $ split (== LineBreak) inlines
195198
196199split :: (a -> Bool) -> [a] -> [[a]]
197200split _ [] = []
@@ -311,9 +314,6 @@ isMimeType s =
311314footnoteID :: Int -> String
312315footnoteID i = "n" ++ show i
313316
314−linkID :: Int -> String
315−linkID i = "l" ++ show i
316−
317317-- | Convert a block-level Pandoc's element to FictionBook XML representation.
318318blockToXml :: PandocMonad m => Block -> FBM m [Content]
319319blockToXml (Plain ss) = cMapM toXml ss -- FIXME: can lead to malformed FB2
@@ -365,10 +365,7 @@ blockToXml h@Header{} = do
365365 -- should not occur after hierarchicalize, except inside lists/blockquotes
366366 report $ BlockNotRendered h
367367 return []
368−blockToXml HorizontalRule = return
369− [ el "empty-line" ()
370− , el "p" (txt (replicate 10 '—'))
371− , el "empty-line" () ]
368+blockToXml HorizontalRule = return [ el "empty-line" () ]
372369blockToXml (Table caption aligns _ headers rows) = do
373370 hd <- mkrow "th" headers aligns
374371 bd <- mapM (\r -> mkrow "td" r aligns) rows
@@ -398,7 +395,7 @@ plainToPara [] = []
398395plainToPara (Plain inlines : rest) =
399396 Para inlines : plainToPara rest
400397plainToPara (Para inlines : rest) =
401− Para inlines : Plain [LineBreak] : plainToPara rest
398+ Para inlines : HorizontalRule : plainToPara rest -- HorizontalRule will be converted to <empty-line />
402399plainToPara (p:rest) = p : plainToPara rest
403400
404401-- Simulate increased indentation level. Will not really work
@@ -449,29 +446,15 @@ toXml (Quoted DoubleQuote ss) = do
449446toXml (Cite _ ss) = cMapM toXml ss -- FIXME: support citation styles
450447toXml (Code _ s) = return [el "code" s]
451448toXml Space = return [txt " "]
452−toXml SoftBreak = return [txt " "]
453−toXml LineBreak = return [el "empty-line" ()]
449+toXml SoftBreak = return [txt "\n"]
450+toXml LineBreak = return [txt "\n"]
454451toXml (Math _ formula) = insertMath InlineImage formula
455452toXml il@(RawInline _ _) = do
456453 report $ InlineNotRendered il
457454 return [] -- raw TeX and raw HTML are suppressed
458−toXml (Link _ text (url,ttl)) = do
459− fns <- footnotes `liftM` get
460− let n = 1 + length fns
461− let ln_id = linkID n
462− let ln_ref = list . el "sup" . txt $ "[" ++ show n ++ "]"
455+toXml (Link _ text (url,_)) = do
463456 ln_text <- cMapM toXml text
464− let ln_desc =
465− let ttl' = dropWhile isSpace ttl
466− in if null ttl'
467− then list . el "p" $ el "code" url
468− else list . el "p" $ [ txt (ttl' ++ ": "), el "code" url ]
469− modify (\s -> s { footnotes = (n, ln_id, ln_desc) : fns })
470− return $ ln_text ++
471− [ el "a"
472− ( [ attr ("l","href") ('#':ln_id)
473− , uattr "type" "note" ]
474− , ln_ref) ]
457+ return [ el "a" ( [ attr ("l","href") url ], ln_text) ]
475458toXml img@Image{} = insertImage InlineImage img
476459toXml (Note bs) = do
477460 fns <- footnotes `liftM` get
src/Text/Pandoc/Writers/HTML.hs+31−43
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -45,11 +46,11 @@ module Text.Pandoc.Writers.HTML (
4546 writeRevealJs,
4647 tagWithAttributes
4748 ) where
49+import Prelude
4850import Control.Monad.State.Strict
4951import Data.Char (ord, toLower)
5052import Data.List (intercalate, intersperse, isPrefixOf, partition)
5153import Data.Maybe (catMaybes, fromMaybe, isJust, isNothing)
52−import Data.Monoid ((<>))
5354import qualified Data.Set as Set
5455import Data.String (fromString)
5556import Data.Text (Text)
@@ -259,10 +260,6 @@ pandocToHtml opts (Pandoc meta blocks) = do
259260 notes <- footnoteSection opts (reverse (stNotes st))
260261 let thebody = blocks' >> notes
261262 let math = case writerHTMLMathMethod opts of
262− LaTeXMathML (Just url) ->
263− H.script ! A.src (toValue url)
264− ! A.type_ "text/javascript"
265− $ mempty
266263 MathJax url
267264 | slideVariant /= RevealJsSlides ->
268265 -- mathjax is handled via a special plugin in revealjs
@@ -273,21 +270,15 @@ pandocToHtml opts (Pandoc meta blocks) = do
273270 preEscapedString
274271 "MathJax.Hub.Queue([\"Typeset\",MathJax.Hub]);"
275272 _ -> mempty
276− JsMath (Just url) ->
277− H.script ! A.src (toValue url)
278− ! A.type_ "text/javascript"
279− $ mempty
280− KaTeX url ->
281− (H.script !
282− A.src (toValue $ url ++ "katex.min.js") $ mempty) <>
283− (H.script !
284− A.src (toValue $ url ++ "contrib/auto-render.min.js")
285− $ mempty) <>
286− (
287− H.script
288− "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});") <>
289− (H.link ! A.rel "stylesheet" !
290− A.href (toValue $ url ++ "katex.min.css"))
273+ KaTeX url -> do
274+ H.script !
275+ A.src (toValue $ url ++ "katex.min.js") $ mempty
276+ H.script !
277+ A.src (toValue $ url ++ "contrib/auto-render.min.js") $ mempty
278+ H.script
279+ "document.addEventListener(\"DOMContentLoaded\", function() {\n renderMathInElement(document.body);\n});"
280+ H.link ! A.rel "stylesheet" !
281+ A.href (toValue $ url ++ "katex.min.css")
291282
292283 _ -> case lookup "mathml-script" (writerVariables opts) of
293284 Just s | not (stHtml5 st) ->
@@ -363,7 +354,8 @@ defList :: PandocMonad m
363354defList opts items = toList H.dl opts (items ++ [nl opts])
364355
365356-- | Construct table of contents from list of elements.
366−tableOfContents :: PandocMonad m => WriterOptions -> [Element] -> StateT WriterState m (Maybe Html)
357+tableOfContents :: PandocMonad m => WriterOptions -> [Element]
358+ -> StateT WriterState m (Maybe Html)
367359tableOfContents _ [] = return Nothing
368360tableOfContents opts sects = do
369361 contents <- mapM (elementToListItem opts) sects
@@ -378,7 +370,8 @@ showSecNum = intercalate "." . map show
378370
379371-- | Converts an Element to a list item for a table of contents,
380372-- retrieving the appropriate identifier from state.
381−elementToListItem :: PandocMonad m => WriterOptions -> Element -> StateT WriterState m (Maybe Html)
373+elementToListItem :: PandocMonad m => WriterOptions -> Element
374+ -> StateT WriterState m (Maybe Html)
382375-- Don't include the empty headers created in slide shows
383376-- shows when an hrule is used to separate slides without a new title:
384377elementToListItem _ (Sec _ _ _ [Str "\0"] _) = return Nothing
@@ -390,7 +383,8 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs)
390383 then (H.span ! A.class_ "toc-section-number"
391384 $ toHtml $ showSecNum num') >> preEscapedString " "
392385 else mempty
393− txt <- liftM (sectnum >>) $ inlineListToHtml opts $ walk deNote headerText
386+ txt <- liftM (sectnum >>) $
387+ inlineListToHtml opts $ walk (deLink . deNote) headerText
394388 subHeads <- mapM (elementToListItem opts) subsecs >>= return . catMaybes
395389 subList <- if null subHeads
396390 then return mempty
@@ -406,8 +400,13 @@ elementToListItem opts (Sec lev num (id',classes,_) headerText subsecs)
406400 $ toHtml txt) >> subList
407401elementToListItem _ _ = return Nothing
408402
403+deLink :: Inline -> Inline
404+deLink (Link _ ils _) = Span nullAttr ils
405+deLink x = x
406+
409407-- | Convert an Element to Html.
410−elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element -> StateT WriterState m Html
408+elementToHtml :: PandocMonad m => Int -> WriterOptions -> Element
409+ -> StateT WriterState m Html
411410elementToHtml _slideLevel opts (Blk block) = blockToHtml opts block
412411elementToHtml slideLevel opts (Sec level num (id',classes,keyvals) title' elements) = do
413412 slideVariant <- gets stSlideVariant
@@ -479,7 +478,12 @@ footnoteSection opts notes = do
479478 html5 <- gets stHtml5
480479 slideVariant <- gets stSlideVariant
481480 let hrtag = if html5 then H5.hr else H.hr
481+ epubVersion <- gets stEPUBVersion
482482 let container x
483+ | html5
484+ , epubVersion == Just EPUB3
485+ = H5.section ! A.class_ "footnotes"
486+ ! customAttribute "epub:type" "footnotes" $ x
483487 | html5 = H5.section ! A.class_ "footnotes" $ x
484488 | slideVariant /= NoSlides = H.div ! A.class_ "footnotes slide" $ x
485489 | otherwise = H.div ! A.class_ "footnotes" $ x
@@ -962,8 +966,9 @@ inlineToHtml opts inline = do
962966 WrapNone -> preEscapedString " "
963967 WrapAuto -> preEscapedString " "
964968 WrapPreserve -> preEscapedString "\n"
965− LineBreak -> return $ (if html5 then H5.br else H.br)
966− <> strToHtml "\n"
969+ LineBreak -> return $ do
970+ if html5 then H5.br else H.br
971+ strToHtml "\n"
967972 (Span (id',classes,kvs) ils)
968973 -> inlineListToHtml opts ils >>=
969974 addAttrs opts attr' . H.span
@@ -1019,19 +1024,6 @@ inlineToHtml opts inline = do
10191024 let mathClass = toValue $ ("math " :: String) ++
10201025 if t == InlineMath then "inline" else "display"
10211026 case writerHTMLMathMethod opts of
1022− LaTeXMathML _ ->
1023− -- putting LaTeXMathML in container with class "LaTeX" prevents
1024− -- non-math elements on the page from being treated as math by
1025− -- the javascript
1026− return $ H.span ! A.class_ "LaTeX" $
1027− case t of
1028− InlineMath -> toHtml ("$" ++ str ++ "$")
1029− DisplayMath -> toHtml ("$$" ++ str ++ "$$")
1030− JsMath _ -> do
1031− let m = preEscapedString str
1032− return $ case t of
1033− InlineMath -> H.span ! A.class_ mathClass $ m
1034− DisplayMath -> H.div ! A.class_ mathClass $ m
10351027 WebTeX url -> do
10361028 let imtag = if html5 then H5.img else H.img
10371029 let m = imtag ! A.style "vertical-align:middle"
@@ -1042,10 +1034,6 @@ inlineToHtml opts inline = do
10421034 return $ case t of
10431035 InlineMath -> m
10441036 DisplayMath -> brtag >> m >> brtag
1045− GladTeX ->
1046− return $ case t of
1047− InlineMath -> preEscapedString $ "<EQ ENV=\"math\">" ++ str ++ "</EQ>"
1048− DisplayMath -> preEscapedString $ "<EQ ENV=\"displaymath\">" ++ str ++ "</EQ>"
10491037 MathML -> do
10501038 let conf = useShortEmptyTags (const False)
10511039 defaultConfigPP
src/Text/Pandoc/Writers/Haddock.hs+7−60
@@ -1,6 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE ScopedTypeVariables #-}
3−{-# LANGUAGE TupleSections #-}
4+
45{-
56Copyright (C) 2014-2015, 2017-2018 John MacFarlane <jgm@berkeley.edu>
67
@@ -33,9 +34,9 @@ Conversion of 'Pandoc' documents to haddock markup.
3334Haddock: <http://www.haskell.org/haddock/doc/html/>
3435-}
3536module Text.Pandoc.Writers.Haddock (writeHaddock) where
37+import Prelude
3638import Control.Monad.State.Strict
3739import Data.Default
38−import Data.List (intersperse, transpose)
3940import Data.Text (Text)
4041import Text.Pandoc.Class (PandocMonad, report)
4142import Text.Pandoc.Definition
@@ -136,29 +137,15 @@ blockToHaddock _ (CodeBlock (_,_,_) str) =
136137-- Nothing in haddock corresponds to block quotes:
137138blockToHaddock opts (BlockQuote blocks) =
138139 blockListToHaddock opts blocks
139−-- Haddock doesn't have tables. Use haddock tables in code.
140140blockToHaddock opts (Table caption aligns widths headers rows) = do
141141 caption' <- inlineListToHaddock opts caption
142142 let caption'' = if null caption
143143 then empty
144144 else blankline <> caption' <> blankline
145− rawHeaders <- mapM (blockListToHaddock opts) headers
146− rawRows <- mapM (mapM (blockListToHaddock opts)) rows
147− let isSimple = all (==0) widths
148− let isPlainBlock (Plain _) = True
149− isPlainBlock _ = False
150− let hasBlocks = not (all isPlainBlock $ concat . concat $ headers:rows)
151− (nst,tbl) <- case True of
152− _ | isSimple -> (nest 2,) <$>
153− pandocTable opts (all null headers) aligns widths
154− rawHeaders rawRows
155− | not hasBlocks -> (nest 2,) <$>
156− pandocTable opts (all null headers) aligns widths
157− rawHeaders rawRows
158− | otherwise -> (id,) <$>
159− gridTable opts blockListToHaddock
160− (all null headers) aligns widths headers rows
161− return $ prefixed "> " (nst $ tbl $$ blankline $$ caption'') $$ blankline
145+ tbl <- gridTable opts blockListToHaddock
146+ (all null headers) (map (const AlignDefault) aligns)
147+ widths headers rows
148+ return $ prefixed "> " (tbl $$ blankline $$ caption'') $$ blankline
162149blockToHaddock opts (BulletList items) = do
163150 contents <- mapM (bulletListItemToHaddock opts) items
164151 return $ cat contents <> blankline
@@ -174,46 +161,6 @@ blockToHaddock opts (DefinitionList items) = do
174161 contents <- mapM (definitionListItemToHaddock opts) items
175162 return $ cat contents <> blankline
176163
177−pandocTable :: PandocMonad m
178− => WriterOptions -> Bool -> [Alignment] -> [Double]
179− -> [Doc] -> [[Doc]] -> StateT WriterState m Doc
180−pandocTable opts headless aligns widths rawHeaders rawRows = do
181− let isSimple = all (==0) widths
182− let alignHeader alignment = case alignment of
183− AlignLeft -> lblock
184− AlignCenter -> cblock
185− AlignRight -> rblock
186− AlignDefault -> lblock
187− let numChars = maximum . map offset
188− let widthsInChars = if isSimple
189− then map ((+2) . numChars)
190− $ transpose (rawHeaders : rawRows)
191− else map
192− (floor . (fromIntegral (writerColumns opts) *))
193− widths
194− let makeRow = hcat . intersperse (lblock 1 (text " ")) .
195− zipWith3 alignHeader aligns widthsInChars
196− let rows' = map makeRow rawRows
197− let head' = makeRow rawHeaders
198− let maxRowHeight = maximum $ map height (head':rows')
199− let underline = cat $ intersperse (text " ") $
200− map (\width -> text (replicate width '-')) widthsInChars
201− let border
202− | maxRowHeight > 1 = text (replicate (sum widthsInChars +
203− length widthsInChars - 1) '-')
204− | headless = underline
205− | otherwise = empty
206− let head'' = if headless
207− then empty
208− else border <> cr <> head'
209− let body = if maxRowHeight > 1
210− then vsep rows'
211− else vcat rows'
212− let bottom = if headless
213− then underline
214− else border
215− return $ head'' $$ underline $$ body $$ bottom
216−
217164-- | Convert bullet list item (list of blocks) to haddock
218165bulletListItemToHaddock :: PandocMonad m
219166 => WriterOptions -> [Block] -> StateT WriterState m Doc
src/Text/Pandoc/Writers/ICML.hs+4−2
@@ -1,5 +1,6 @@
1−{-# LANGUAGE FlexibleContexts #-}
2−{-# LANGUAGE OverloadedStrings #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE FlexibleContexts #-}
3+{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE ScopedTypeVariables #-}
45
56{- |
@@ -16,6 +17,7 @@ InCopy is the companion word-processor to Adobe InDesign and ICML documents can
1617into InDesign with File -> Place.
1718-}
1819module Text.Pandoc.Writers.ICML (writeICML) where
20+import Prelude
1921import Control.Monad.Except (catchError)
2022import Control.Monad.State.Strict
2123import Data.List (intersperse, isInfixOf, isPrefixOf, stripPrefix)
src/Text/Pandoc/Writers/JATS.hs+8−6
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23
34{-
@@ -28,9 +29,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2829
2930Conversion of 'Pandoc' documents to JATS XML.
3031Reference:
31−https://jats.nlm.nih.gov/publishing/tag-library/1.1d3/element/mml-math.html
32+https://jats.nlm.nih.gov/publishing/tag-library
3233-}
3334module Text.Pandoc.Writers.JATS ( writeJATS ) where
35+import Prelude
3436import Control.Monad.Reader
3537import Data.Char (toLower)
3638import Data.Generics (everywhere, mkT)
@@ -139,7 +141,7 @@ deflistItemToJATS opts term defs = do
139141 term' <- inlinesToJATS opts term
140142 def' <- blocksToJATS opts $ concatMap (map plainToPara) defs
141143 return $ inTagsIndented "def-item" $
142− inTagsIndented "term" term' $$
144+ inTagsSimple "term" term' $$
143145 inTagsIndented "def" def'
144146
145147-- | Convert a list of lists of blocks to a list of JATS list items.
@@ -156,7 +158,7 @@ listItemToJATS :: PandocMonad m
156158listItemToJATS opts mbmarker item = do
157159 contents <- blocksToJATS opts item
158160 return $ inTagsIndented "list-item" $
159− maybe empty (\lbl -> inTagsIndented "label" (text lbl)) mbmarker
161+ maybe empty (\lbl -> inTagsSimple "label" (text lbl)) mbmarker
160162 $$ contents
161163
162164imageMimeType :: String -> [(String, String)] -> (String, String)
@@ -250,7 +252,7 @@ blockToJATS _ (Para [Image (ident,_,kvs) _ (src, tit)]) = do
250252 "xlink:type"]]
251253 return $ selfClosingTag "graphic" attr
252254blockToJATS opts (Para lst) =
253− inTagsIndented "p" <$> inlinesToJATS opts lst
255+ inTagsSimple "p" <$> inlinesToJATS opts lst
254256blockToJATS opts (LineBlock lns) =
255257 blockToJATS opts $ linesToPara lns
256258blockToJATS opts (BlockQuote blocks) =
@@ -326,10 +328,10 @@ tableItemToJATS :: PandocMonad m
326328 -> [Block]
327329 -> JATS m Doc
328330tableItemToJATS opts isHeader [Plain item] =
329− inTags True (if isHeader then "th" else "td") [] <$>
331+ inTags False (if isHeader then "th" else "td") [] <$>
330332 inlinesToJATS opts item
331333tableItemToJATS opts isHeader item =
332− (inTags True (if isHeader then "th" else "td") [] . vcat) <$>
334+ (inTags False (if isHeader then "th" else "td") [] . vcat) <$>
333335 mapM (blockToJATS opts) item
334336
335337-- | Convert a list of inline elements to JATS.
src/Text/Pandoc/Writers/LaTeX.hs+12−9
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE PatternGuards #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -34,6 +35,7 @@ module Text.Pandoc.Writers.LaTeX (
3435 writeLaTeX
3536 , writeBeamer
3637 ) where
38+import Prelude
3739import Control.Applicative ((<|>))
3840import Control.Monad.State.Strict
3941import Data.Aeson (FromJSON, object, (.=))
@@ -411,15 +413,15 @@ elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
411413 slideTitle <-
412414 if tit == [Str "\0"] -- marker for hrule
413415 then return []
414− else
415− if null ident
416− then return $ latex "{" : tit ++ [latex "}"]
417− else do
418− ref <- toLabel ident
419− return $ latex ("{%\n\\protect\\hypertarget{" ++
420− ref ++ "}{%\n") : tit ++ [latex "}}"]
416+ else return $ latex "{" : tit ++ [latex "}"]
417+ ref <- toLabel ident
418+ let slideAnchor = if null ident
419+ then []
420+ else [latex ("\n\\protect\\hypertarget{" ++
421+ ref ++ "}{}")]
421422 let slideStart = Para $
422− RawInline "latex" ("\\begin{frame}" ++ options) : slideTitle
423+ RawInline "latex" ("\\begin{frame}" ++ options) :
424+ slideTitle ++ slideAnchor
423425 let slideEnd = RawBlock "latex" "\\end{frame}"
424426 -- now carve up slide into blocks if there are sections inside
425427 bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
@@ -676,6 +678,7 @@ blockToLaTeX (OrderedList (start, numstyle, numdelim) lst) = do
676678 let enum = text $ "enum" ++ map toLower (toRomanNumeral oldlevel)
677679 let stylecommand
678680 | numstyle == DefaultStyle && numdelim == DefaultDelim = empty
681+ | beamer && numstyle == Decimal && numdelim == Period = empty
679682 | beamer = brackets (todelim exemplar)
680683 | otherwise = "\\def" <> "\\label" <> enum <>
681684 braces (todelim $ tostyle enum)
@@ -1033,7 +1036,7 @@ inlineToLaTeX (Code (_,classes,_) str) = do
10331036 Nothing -> ""
10341037 inNote <- gets stInNote
10351038 when inNote $ modify $ \s -> s{ stVerbInNote = True }
1036− let chr = case "!\"&'()*,-./:;?@_" \\ str of
1039+ let chr = case "!\"'()*,-./:;?@" \\ str of
10371040 (c:_) -> c
10381041 [] -> '!'
10391042 let str' = escapeStringUsing (backslashEscapes "\\{}%~_&") str
src/Text/Pandoc/Writers/Man.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to groff man page format.
3031
3132-}
3233module Text.Pandoc.Writers.Man ( writeMan) where
34+import Prelude
3335import Control.Monad.State.Strict
3436import Data.List (intercalate, intersperse, sort, stripPrefix)
3537import qualified Data.Map as Map
src/Text/Pandoc/Writers/Markdown.hs+6−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE MultiWayIf #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE ScopedTypeVariables #-}
@@ -34,6 +35,7 @@ Conversion of 'Pandoc' documents to markdown-formatted plain text.
3435Markdown: <http://daringfireball.net/projects/markdown/>
3536-}
3637module Text.Pandoc.Writers.Markdown (writeMarkdown, writePlain) where
38+import Prelude
3739import Control.Monad.Reader
3840import Control.Monad.State.Strict
3941import Data.Char (chr, isPunctuation, isSpace, ord, isAlphaNum)
@@ -730,7 +732,10 @@ pandocTable opts multiline headless aligns widths rawHeaders rawRows = do
730732 then empty
731733 else border <> cr <> head'
732734 let body = if multiline
733− then vsep rows'
735+ then vsep rows' $$
736+ if length rows' < 2
737+ then blankline -- #4578
738+ else empty
734739 else vcat rows'
735740 let bottom = if headless
736741 then underline
src/Text/Pandoc/Writers/Math.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Text.Pandoc.Writers.Math
23 ( texMathToInlines
34 , convertMath
@@ -6,6 +7,7 @@ module Text.Pandoc.Writers.Math
67 )
78where
89
10+import Prelude
911import Text.Pandoc.Class
1012import Text.Pandoc.Definition
1113import Text.Pandoc.Logging
src/Text/Pandoc/Writers/MediaWiki.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to MediaWiki markup.
3031MediaWiki: <http://www.mediawiki.org/wiki/MediaWiki>
3132-}
3233module Text.Pandoc.Writers.MediaWiki ( writeMediaWiki ) where
34+import Prelude
3335import Control.Monad.Reader
3436import Control.Monad.State.Strict
3537import Data.List (intercalate)
src/Text/Pandoc/Writers/Ms.hs+37−11
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2007-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -36,9 +37,10 @@ TODO:
3637-}
3738
3839module Text.Pandoc.Writers.Ms ( writeMs ) where
40+import Prelude
3941import Control.Monad.State.Strict
40−import Data.Char (isLower, isUpper, toUpper)
41−import Data.List (intercalate, intersperse, sort)
42+import Data.Char (isLower, isUpper, toUpper, ord)
43+import Data.List (intercalate, intersperse)
4244import qualified Data.Map as Map
4345import Data.Maybe (catMaybes, fromMaybe)
4446import Data.Text (Text)
@@ -46,6 +48,7 @@ import qualified Data.Text as T
4648import Network.URI (escapeURIString, isAllowedInURI)
4749import Skylighting
4850import System.FilePath (takeExtension)
51+import Text.Pandoc.Asciify (toAsciiChar)
4952import Text.Pandoc.Class (PandocMonad, report)
5053import Text.Pandoc.Definition
5154import Text.Pandoc.Highlighting
@@ -65,6 +68,7 @@ data WriterState = WriterState { stHasInlineMath :: Bool
6568 , stNotes :: [Note]
6669 , stSmallCaps :: Bool
6770 , stHighlighting :: Bool
71+ , stInHeader :: Bool
6872 , stFontFeatures :: Map.Map Char Bool
6973 }
7074
@@ -74,6 +78,7 @@ defaultWriterState = WriterState{ stHasInlineMath = False
7478 , stNotes = []
7579 , stSmallCaps = False
7680 , stHighlighting = False
81+ , stInHeader = False
7782 , stFontFeatures = Map.fromList [
7883 ('I',False)
7984 , ('B',False)
@@ -132,14 +137,12 @@ msEscapes = Map.fromList
132137 [ ('\160', "\\~")
133138 , ('\'', "\\[aq]")
134139 , ('`', "\\`")
135− , ('\8217', "'")
136140 , ('"', "\\[dq]")
137141 , ('\x2014', "\\[em]")
138142 , ('\x2013', "\\[en]")
139143 , ('\x2026', "\\&...")
140144 , ('~', "\\[ti]")
141145 , ('^', "\\[ha]")
142− , ('-', "\\-")
143146 , ('@', "\\@")
144147 , ('\\', "\\\\")
145148 ]
@@ -216,11 +219,16 @@ blockToMs :: PandocMonad m
216219 -> Block -- ^ Block element
217220 -> MS m Doc
218221blockToMs _ Null = return empty
219−blockToMs opts (Div _ bs) = do
222+blockToMs opts (Div (ident,_,_) bs) = do
223+ let anchor = if null ident
224+ then empty
225+ else nowrap $
226+ text ".pdfhref M "
227+ <> doubleQuotes (text (toAscii ident))
220228 setFirstPara
221229 res <- blockListToMs opts bs
222230 setFirstPara
223− return res
231+ return $ anchor $$ res
224232blockToMs opts (Plain inlines) =
225233 liftM vcat $ mapM (inlineListToMs' opts) $ splitSentences inlines
226234blockToMs opts (Para [Image attr alt (src,_tit)])
@@ -258,7 +266,9 @@ blockToMs _ HorizontalRule = do
258266 return $ text ".HLINE"
259267blockToMs opts (Header level (ident,classes,_) inlines) = do
260268 setFirstPara
269+ modify $ \st -> st{ stInHeader = True }
261270 contents <- inlineListToMs' opts $ map breakToSpace inlines
271+ modify $ \st -> st{ stInHeader = False }
262272 let (heading, secnum) = if writerNumberSections opts &&
263273 "unnumbered" `notElem` classes
264274 then (".NH", "\\*[SN]")
@@ -266,7 +276,8 @@ blockToMs opts (Header level (ident,classes,_) inlines) = do
266276 let anchor = if null ident
267277 then empty
268278 else nowrap $
269− text ".pdfhref M " <> doubleQuotes (text ident)
279+ text ".pdfhref M "
280+ <> doubleQuotes (text (toAscii ident))
270281 let bookmark = text ".pdfhref O " <> text (show level ++ " ") <>
271282 doubleQuotes (text $ secnum ++
272283 (if null secnum
@@ -274,7 +285,7 @@ blockToMs opts (Header level (ident,classes,_) inlines) = do
274285 else " ") ++
275286 escapeString (stringify inlines))
276287 let backlink = nowrap (text ".pdfhref L -D " <>
277− doubleQuotes (text ident) <> space <> text "\\") <> cr <>
288+ doubleQuotes (text (toAscii ident)) <> space <> text "\\") <> cr <>
278289 text " -- "
279290 let tocEntry = if writerTableOfContents opts &&
280291 level <= writerTOCDepth opts
@@ -513,7 +524,7 @@ inlineToMs opts (Link _ txt ('#':ident, _)) = do
513524 -- internal link
514525 contents <- inlineListToMs' opts $ map breakToSpace txt
515526 return $ text "\\c" <> cr <> nowrap (text ".pdfhref L -D " <>
516− doubleQuotes (text ident) <> text " -A " <>
527+ doubleQuotes (text (toAscii ident)) <> text " -A " <>
517528 doubleQuotes (text "\\c") <> space <> text "\\") <> cr <>
518529 text " -- " <> doubleQuotes (nowrap contents) <> cr <> text "\\&"
519530inlineToMs opts (Link _ txt (src, _)) = do
@@ -552,8 +563,15 @@ handleNote opts bs = do
552563fontChange :: PandocMonad m => MS m Doc
553564fontChange = do
554565 features <- gets stFontFeatures
555− let filling = sort [c | (c,True) <- Map.toList features]
556− return $ text $ "\\f[" ++ filling ++ "]"
566+ inHeader <- gets stInHeader
567+ let filling = ['C' | fromMaybe False $ Map.lookup 'C' features] ++
568+ ['B' | inHeader ||
569+ fromMaybe False (Map.lookup 'B' features)] ++
570+ ['I' | fromMaybe False $ Map.lookup 'I' features]
571+ return $
572+ if null filling
573+ then text "\\f[R]"
574+ else text $ "\\f[" ++ filling ++ "]"
557575
558576withFontFeature :: PandocMonad m => Char -> MS m Doc -> MS m Doc
559577withFontFeature c action = do
@@ -637,3 +655,11 @@ highlightCode opts attr str =
637655 Right h -> do
638656 modify (\st -> st{ stHighlighting = True })
639657 return h
658+
659+-- This is used for PDF anchors.
660+toAscii :: String -> String
661+toAscii = concatMap
662+ (\c -> case toAsciiChar c of
663+ Nothing -> '_':'u':show (ord c) ++ "_"
664+ Just '/' -> '_':'u':show (ord c) ++ "_" -- see #4515
665+ Just c' -> [c'])
src/Text/Pandoc/Writers/Muse.hs+238−100
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2017-2018 Alexander Krotov <ilabdsf@gmail.com>
@@ -42,7 +43,11 @@ However, @\<literal style="html">@ tag is used for HTML raw blocks
4243even though it is supported only in Emacs Muse.
4344-}
4445module Text.Pandoc.Writers.Muse (writeMuse) where
46+import Prelude
47+import Control.Monad.Reader
4548import Control.Monad.State.Strict
49+import Data.Char (isSpace, isDigit, isAsciiUpper, isAsciiLower)
50+import Data.Default
4651import Data.Text (Text)
4752import Data.List (intersperse, transpose, isInfixOf)
4853import System.FilePath (takeExtension)
@@ -58,34 +63,54 @@ import Text.Pandoc.Writers.Shared
5863import qualified Data.Set as Set
5964
6065type Notes = [[Block]]
66+
67+type Muse m = ReaderT WriterEnv (StateT WriterState m)
68+
69+data WriterEnv =
70+ WriterEnv { envOptions :: WriterOptions
71+ , envTopLevel :: Bool
72+ , envInsideBlock :: Bool
73+ , envInlineStart :: Bool
74+ , envInsideLinkDescription :: Bool -- ^ Escape ] if True
75+ , envAfterSpace :: Bool
76+ , envOneLine :: Bool -- ^ True if newlines are not allowed
77+ }
78+
6179data WriterState =
6280 WriterState { stNotes :: Notes
63− , stOptions :: WriterOptions
64− , stTopLevel :: Bool
65− , stInsideBlock :: Bool
6681 , stIds :: Set.Set String
6782 }
6883
84+instance Default WriterState
85+ where def = WriterState { stNotes = []
86+ , stIds = Set.empty
87+ }
88+
89+evalMuse :: PandocMonad m => Muse m a -> WriterEnv -> WriterState -> m a
90+evalMuse document env = evalStateT $ runReaderT document env
91+
6992-- | Convert Pandoc to Muse.
7093writeMuse :: PandocMonad m
7194 => WriterOptions
7295 -> Pandoc
7396 -> m Text
7497writeMuse opts document =
75− let st = WriterState { stNotes = []
76− , stOptions = opts
77− , stTopLevel = True
78− , stInsideBlock = False
79− , stIds = Set.empty
80− }
81− in evalStateT (pandocToMuse document) st
98+ evalMuse (pandocToMuse document) env def
99+ where env = WriterEnv { envOptions = opts
100+ , envTopLevel = True
101+ , envInsideBlock = False
102+ , envInlineStart = True
103+ , envInsideLinkDescription = False
104+ , envAfterSpace = False
105+ , envOneLine = False
106+ }
82107
83108-- | Return Muse representation of document.
84109pandocToMuse :: PandocMonad m
85110 => Pandoc
86− -> StateT WriterState m Text
111+ -> Muse m Text
87112pandocToMuse (Pandoc meta blocks) = do
88− opts <- gets stOptions
113+ opts <- asks envOptions
89114 let colwidth = if writerWrapText opts == WrapAuto
90115 then Just $ writerColumns opts
91116 else Nothing
@@ -96,7 +121,7 @@ pandocToMuse (Pandoc meta blocks) = do
96121 (fmap render' . inlineListToMuse)
97122 meta
98123 body <- blockListToMuse blocks
99− notes <- liftM (reverse . stNotes) get >>= notesToMuse
124+ notes <- fmap (reverse . stNotes) get >>= notesToMuse
100125 let main = render colwidth $ body $+$ notes
101126 let context = defField "body" main metadata
102127 case writerTemplate opts of
@@ -108,7 +133,7 @@ pandocToMuse (Pandoc meta blocks) = do
108133catWithBlankLines :: PandocMonad m
109134 => [Block] -- ^ List of block elements
110135 -> Int -- ^ Number of blank lines
111− -> StateT WriterState m Doc
136+ -> Muse m Doc
112137catWithBlankLines (b : bs) n = do
113138 b' <- blockToMuse b
114139 bs' <- flatBlockListToMuse bs
@@ -116,10 +141,10 @@ catWithBlankLines (b : bs) n = do
116141catWithBlankLines _ _ = error "Expected at least one block"
117142
118143-- | Convert list of Pandoc block elements to Muse
119−-- | without setting stTopLevel.
144+-- | without setting envTopLevel.
120145flatBlockListToMuse :: PandocMonad m
121146 => [Block] -- ^ List of block elements
122− -> StateT WriterState m Doc
147+ -> Muse m Doc
123148flatBlockListToMuse bs@(BulletList _ : BulletList _ : _) = catWithBlankLines bs 2
124149flatBlockListToMuse bs@(OrderedList (_, style1, _) _ : OrderedList (_, style2, _) _ : _) =
125150 catWithBlankLines bs (if style1' == style2' then 2 else 0)
@@ -135,36 +160,23 @@ flatBlockListToMuse [] = return mempty
135160-- | Convert list of Pandoc block elements to Muse.
136161blockListToMuse :: PandocMonad m
137162 => [Block] -- ^ List of block elements
138− -> StateT WriterState m Doc
139−blockListToMuse blocks = do
140− oldState <- get
141− modify $ \s -> s { stTopLevel = not $ stInsideBlock s
142− , stInsideBlock = True
143− }
144− result <- flatBlockListToMuse blocks
145− modify $ \s -> s { stTopLevel = stTopLevel oldState
146− , stInsideBlock = stInsideBlock oldState
147− }
148− return result
163+ -> Muse m Doc
164+blockListToMuse =
165+ local (\env -> env { envTopLevel = not (envInsideBlock env)
166+ , envInsideBlock = True
167+ }) . flatBlockListToMuse
149168
150169-- | Convert Pandoc block element to Muse.
151170blockToMuse :: PandocMonad m
152171 => Block -- ^ Block element
153− -> StateT WriterState m Doc
154−blockToMuse (Plain inlines) = inlineListToMuse inlines
172+ -> Muse m Doc
173+blockToMuse (Plain inlines) = inlineListToMuse' inlines
155174blockToMuse (Para inlines) = do
156− contents <- inlineListToMuse inlines
175+ contents <- inlineListToMuse' inlines
157176 return $ contents <> blankline
158177blockToMuse (LineBlock lns) = do
159− let splitStanza [] = []
160− splitStanza xs = case break (== mempty) xs of
161− (l, []) -> [l]
162− (l, _:r) -> l : splitStanza r
163− let joinWithLinefeeds = nowrap . mconcat . intersperse cr
164− let joinWithBlankLines = mconcat . intersperse blankline
165− let prettyfyStanza ls = joinWithLinefeeds <$> mapM inlineListToMuse ls
166− contents <- joinWithBlankLines <$> mapM prettyfyStanza (splitStanza lns)
167− return $ blankline $$ "<verse>" $$ contents $$ "</verse>" <> blankline
178+ lns' <- local (\env -> env { envOneLine = True }) $ mapM inlineListToMuse lns
179+ return $ nowrap $ vcat (map (text "> " <>) lns') <> blankline
168180blockToMuse (CodeBlock (_,_,_) str) =
169181 return $ "<example>" $$ text str $$ "</example>" $$ blankline
170182blockToMuse (RawBlock (Format format) str) =
@@ -180,50 +192,48 @@ blockToMuse (BlockQuote blocks) = do
180192blockToMuse (OrderedList (start, style, _) items) = do
181193 let markers = take (length items) $ orderedListMarkers
182194 (start, style, Period)
183− let maxMarkerLength = maximum $ map length markers
184− let markers' = map (\m -> let s = maxMarkerLength - length m
185− in m ++ replicate s ' ') markers
186− contents <- zipWithM orderedListItemToMuse markers' items
195+ contents <- zipWithM orderedListItemToMuse markers items
187196 -- ensure that sublists have preceding blank line
188− topLevel <- gets stTopLevel
197+ topLevel <- asks envTopLevel
189198 return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
190199 where orderedListItemToMuse :: PandocMonad m
191200 => String -- ^ marker for list item
192201 -> [Block] -- ^ list item (list of blocks)
193− -> StateT WriterState m Doc
202+ -> Muse m Doc
194203 orderedListItemToMuse marker item = do
195− contents <- blockListToMuse item
196− return $ hang (length marker + 1) (text marker <> space) contents
204+ contents <- blockListToMuse item
205+ return $ hang (length marker + 1) (text marker <> space) contents
197206blockToMuse (BulletList items) = do
198207 contents <- mapM bulletListItemToMuse items
199208 -- ensure that sublists have preceding blank line
200− topLevel <- gets stTopLevel
209+ topLevel <- asks envTopLevel
201210 return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
202211 where bulletListItemToMuse :: PandocMonad m
203212 => [Block]
204− -> StateT WriterState m Doc
213+ -> Muse m Doc
205214 bulletListItemToMuse item = do
206215 contents <- blockListToMuse item
207216 return $ hang 2 "- " contents
208217blockToMuse (DefinitionList items) = do
209218 contents <- mapM definitionListItemToMuse items
210− return $ cr $$ nest 1 (vcat contents) $$ blankline
219+ -- ensure that sublists have preceding blank line
220+ topLevel <- asks envTopLevel
221+ return $ cr $$ (if topLevel then nest 1 else id) (vcat contents) $$ blankline
211222 where definitionListItemToMuse :: PandocMonad m
212223 => ([Inline], [[Block]])
213− -> StateT WriterState m Doc
224+ -> Muse m Doc
214225 definitionListItemToMuse (label, defs) = do
215− label' <- inlineListToMuse label
216− contents <- liftM vcat $ mapM descriptionToMuse defs
226+ label' <- local (\env -> env { envOneLine = True, envAfterSpace = True }) $ inlineListToMuse' label
227+ contents <- vcat <$> mapM descriptionToMuse defs
217228 let ind = offset label'
218229 return $ hang ind label' contents
219230 descriptionToMuse :: PandocMonad m
220231 => [Block]
221− -> StateT WriterState m Doc
232+ -> Muse m Doc
222233 descriptionToMuse desc = hang 4 " :: " <$> blockListToMuse desc
223234blockToMuse (Header level (ident,_,_) inlines) = do
224− opts <- gets stOptions
225− contents <- inlineListToMuse inlines
226−
235+ opts <- asks envOptions
236+ contents <- local (\env -> env { envOneLine = True }) $ inlineListToMuse' inlines
227237 ids <- gets stIds
228238 let autoId = uniqueIdent inlines ids
229239 modify $ \st -> st{ stIds = Set.insert autoId ids }
@@ -232,8 +242,7 @@ blockToMuse (Header level (ident,_,_) inlines) = do
232242 then empty
233243 else "#" <> text ident <> cr
234244 let header' = text $ replicate level '*'
235− return $ blankline <> nowrap (header' <> space <> contents)
236− $$ attr' <> blankline
245+ return $ blankline <> attr' $$ nowrap (header' <> space <> contents) <> blankline
237246-- https://www.gnu.org/software/emacs-muse/manual/muse.html#Horizontal-Rules-and-Anchors
238247blockToMuse HorizontalRule = return $ blankline $$ "----" $$ blankline
239248blockToMuse (Table caption _ _ headers rows) = do
@@ -266,18 +275,18 @@ blockToMuse Null = return empty
266275-- | Return Muse representation of notes.
267276notesToMuse :: PandocMonad m
268277 => Notes
269− -> StateT WriterState m Doc
270−notesToMuse notes = liftM vsep (zipWithM noteToMuse [1 ..] notes)
278+ -> Muse m Doc
279+notesToMuse notes = vsep <$> zipWithM noteToMuse [1 ..] notes
271280
272281-- | Return Muse representation of a note.
273282noteToMuse :: PandocMonad m
274283 => Int
275284 -> [Block]
276− -> StateT WriterState m Doc
277−noteToMuse num note = do
278− contents <- blockListToMuse note
279− let marker = "[" ++ show num ++ "] "
280− return $ hang (length marker) (text marker) contents
285+ -> Muse m Doc
286+noteToMuse num note =
287+ hang (length marker) (text marker) <$> blockListToMuse note
288+ where
289+ marker = "[" ++ show num ++ "] "
281290
282291-- | Escape special characters for Muse.
283292escapeString :: String -> String
@@ -286,17 +295,74 @@ escapeString s =
286295 substitute "</verbatim>" "<</verbatim><verbatim>/verbatim>" s ++
287296 "</verbatim>"
288297
298+startsWithMarker :: (Char -> Bool) -> String -> Bool
299+startsWithMarker f (' ':xs) = startsWithMarker f xs
300+startsWithMarker f (x:xs) =
301+ f x && (startsWithMarker f xs || startsWithDot xs)
302+ where
303+ startsWithDot ['.'] = True
304+ startsWithDot ('.':c:_) = isSpace c
305+ startsWithDot _ = False
306+startsWithMarker _ [] = False
307+
289308-- | Escape special characters for Muse if needed.
290−conditionalEscapeString :: String -> String
291−conditionalEscapeString s =
292− if any (`elem` ("#*<=>[]|" :: String)) s ||
309+containsFootnotes :: String -> Bool
310+containsFootnotes = p
311+ where p ('[':xs) = q xs || p xs
312+ p (_:xs) = p xs
313+ p "" = False
314+ q (x:xs)
315+ | x `elem` ("123456789"::String) = r xs || p xs
316+ | otherwise = p xs
317+ q [] = False
318+ r ('0':xs) = r xs || p xs
319+ r xs = s xs || q xs || p xs
320+ s (']':_) = True
321+ s (_:xs) = p xs
322+ s [] = False
323+
324+conditionalEscapeString :: Bool -> String -> String
325+conditionalEscapeString isInsideLinkDescription s =
326+ if any (`elem` ("#*<=|" :: String)) s ||
293327 "::" `isInfixOf` s ||
294− "----" `isInfixOf` s ||
295− "~~" `isInfixOf` s
328+ "~~" `isInfixOf` s ||
329+ "[[" `isInfixOf` s ||
330+ ("]" `isInfixOf` s && isInsideLinkDescription) ||
331+ containsFootnotes s
296332 then escapeString s
297333 else s
298334
335+-- Expand Math and Cite before normalizing inline list
336+preprocessInlineList :: PandocMonad m
337+ => [Inline]
338+ -> m [Inline]
339+preprocessInlineList (Math t str:xs) = (++) <$> texMathToInlines t str <*> preprocessInlineList xs
340+-- Amusewiki does not support <cite> tag,
341+-- and Emacs Muse citation support is limited
342+-- (https://www.gnu.org/software/emacs-muse/manual/html_node/Citations.html#Citation)
343+-- so just fallback to expanding inlines.
344+preprocessInlineList (Cite _ lst:xs) = (lst ++) <$> preprocessInlineList xs
345+preprocessInlineList (x:xs) = (x:) <$> preprocessInlineList xs
346+preprocessInlineList [] = return []
347+
348+replaceSmallCaps :: Inline -> Inline
349+replaceSmallCaps (SmallCaps lst) = Emph lst
350+replaceSmallCaps x = x
351+
352+removeKeyValues :: Inline -> Inline
353+removeKeyValues (Code (i, cls, _) xs) = Code (i, cls, []) xs
354+-- Do not remove attributes from Link
355+-- Do not remove attributes, such as "width", from Image
356+removeKeyValues (Span (i, cls, _) xs) = Span (i, cls, []) xs
357+removeKeyValues x = x
358+
299359normalizeInlineList :: [Inline] -> [Inline]
360+normalizeInlineList (Str "" : xs)
361+ = normalizeInlineList xs
362+normalizeInlineList (x : Str "" : xs)
363+ = normalizeInlineList (x:xs)
364+normalizeInlineList (Str x1 : Str x2 : xs)
365+ = normalizeInlineList $ Str (x1 ++ x2) : xs
300366normalizeInlineList (Emph x1 : Emph x2 : ils)
301367 = normalizeInlineList $ Emph (x1 ++ x2) : ils
302368normalizeInlineList (Strong x1 : Strong x2 : ils)
@@ -313,8 +379,7 @@ normalizeInlineList (Code _ x1 : Code _ x2 : ils)
313379 = normalizeInlineList $ Code nullAttr (x1 ++ x2) : ils
314380normalizeInlineList (RawInline f1 x1 : RawInline f2 x2 : ils) | f1 == f2
315381 = normalizeInlineList $ RawInline f1 (x1 ++ x2) : ils
316−normalizeInlineList (Span a1 x1 : Span a2 x2 : ils) | a1 == a2
317− = normalizeInlineList $ Span a1 (x1 ++ x2) : ils
382+-- Do not join Span's during normalization
318383normalizeInlineList (x:xs) = x : normalizeInlineList xs
319384normalizeInlineList [] = []
320385
@@ -324,17 +389,77 @@ fixNotes (Space : n@Note{} : rest) = Str " " : n : fixNotes rest
324389fixNotes (SoftBreak : n@Note{} : rest) = Str " " : n : fixNotes rest
325390fixNotes (x:xs) = x : fixNotes xs
326391
327−-- | Convert list of Pandoc inline elements to Muse.
328−inlineListToMuse :: PandocMonad m
392+urlEscapeBrackets :: String -> String
393+urlEscapeBrackets (']':xs) = '%':'5':'D':urlEscapeBrackets xs
394+urlEscapeBrackets (x:xs) = x:urlEscapeBrackets xs
395+urlEscapeBrackets [] = []
396+
397+isHorizontalRule :: String -> Bool
398+isHorizontalRule s = length s >= 4 && all (== '-') s
399+
400+startsWithSpace :: String -> Bool
401+startsWithSpace (x:_) = isSpace x
402+startsWithSpace [] = False
403+
404+fixOrEscape :: Bool -> Inline -> Bool
405+fixOrEscape sp (Str "-") = sp
406+fixOrEscape sp (Str ";") = not sp
407+fixOrEscape _ (Str ">") = True
408+fixOrEscape sp (Str s) = (sp && (startsWithMarker isDigit s ||
409+ startsWithMarker isAsciiLower s ||
410+ startsWithMarker isAsciiUpper s))
411+ || isHorizontalRule s || startsWithSpace s
412+fixOrEscape _ Space = True
413+fixOrEscape _ SoftBreak = True
414+fixOrEscape _ _ = False
415+
416+-- | Convert list of Pandoc inline elements to Muse
417+renderInlineList :: PandocMonad m
329418 => [Inline]
330− -> StateT WriterState m Doc
331−inlineListToMuse lst = hcat <$> mapM inlineToMuse (fixNotes $ normalizeInlineList lst)
419+ -> Muse m Doc
420+renderInlineList [] = do
421+ start <- asks envInlineStart
422+ pure $ if start then "<verbatim></verbatim>" else ""
423+renderInlineList (x:xs) = do
424+ start <- asks envInlineStart
425+ afterSpace <- asks envAfterSpace
426+ topLevel <- asks envTopLevel
427+ r <- inlineToMuse x
428+ opts <- asks envOptions
429+ let isNewline = (x == SoftBreak && writerWrapText opts == WrapPreserve) || x == LineBreak
430+ lst' <- local (\env -> env { envInlineStart = isNewline
431+ , envAfterSpace = x == Space || (not topLevel && isNewline)
432+ }) $ renderInlineList xs
433+ if start && fixOrEscape afterSpace x
434+ then pure (text "<verbatim></verbatim>" <> r <> lst')
435+ else pure (r <> lst')
436+
437+-- | Normalize and convert list of Pandoc inline elements to Muse.
438+inlineListToMuse'' :: PandocMonad m
439+ => Bool
440+ -> [Inline]
441+ -> Muse m Doc
442+inlineListToMuse'' start lst = do
443+ lst' <- (normalizeInlineList . fixNotes) <$> preprocessInlineList (map (removeKeyValues . replaceSmallCaps) lst)
444+ topLevel <- asks envTopLevel
445+ afterSpace <- asks envAfterSpace
446+ local (\env -> env { envInlineStart = start
447+ , envAfterSpace = afterSpace || (start && not topLevel)
448+ }) $ renderInlineList lst'
449+
450+inlineListToMuse' :: PandocMonad m => [Inline] -> Muse m Doc
451+inlineListToMuse' = inlineListToMuse'' True
452+
453+inlineListToMuse :: PandocMonad m => [Inline] -> Muse m Doc
454+inlineListToMuse = inlineListToMuse'' False
332455
333456-- | Convert Pandoc inline element to Muse.
334457inlineToMuse :: PandocMonad m
335458 => Inline
336− -> StateT WriterState m Doc
337−inlineToMuse (Str str) = return $ text $ conditionalEscapeString str
459+ -> Muse m Doc
460+inlineToMuse (Str str) = do
461+ insideLink <- asks envInsideLinkDescription
462+ return $ text $ conditionalEscapeString insideLink str
338463inlineToMuse (Emph lst) = do
339464 contents <- inlineListToMuse lst
340465 return $ "<em>" <> contents <> "</em>"
@@ -350,60 +475,73 @@ inlineToMuse (Superscript lst) = do
350475inlineToMuse (Subscript lst) = do
351476 contents <- inlineListToMuse lst
352477 return $ "<sub>" <> contents <> "</sub>"
353−inlineToMuse (SmallCaps lst) = inlineListToMuse lst
478+inlineToMuse SmallCaps {} =
479+ fail "SmallCaps should be expanded before normalization"
354480inlineToMuse (Quoted SingleQuote lst) = do
355481 contents <- inlineListToMuse lst
356482 return $ "‘" <> contents <> "’"
357483inlineToMuse (Quoted DoubleQuote lst) = do
358484 contents <- inlineListToMuse lst
359485 return $ "“" <> contents <> "”"
360−-- Amusewiki does not support <cite> tag,
361−-- and Emacs Muse citation support is limited
362−-- (https://www.gnu.org/software/emacs-muse/manual/html_node/Citations.html#Citation)
363−-- so just fallback to expanding inlines.
364−inlineToMuse (Cite _ lst) = inlineListToMuse lst
486+inlineToMuse Cite {} =
487+ fail "Citations should be expanded before normalization"
365488inlineToMuse (Code _ str) = return $
366489 "<code>" <> text (substitute "</code>" "<</code><code>/code>" str) <> "</code>"
367−inlineToMuse (Math t str) =
368− lift (texMathToInlines t str) >>= inlineListToMuse
490+inlineToMuse Math{} =
491+ fail "Math should be expanded before normalization"
369492inlineToMuse (RawInline (Format f) str) =
370493 return $ "<literal style=\"" <> text f <> "\">" <> text str <> "</literal>"
371−inlineToMuse LineBreak = return $ "<br>" <> cr
494+inlineToMuse LineBreak = do
495+ oneline <- asks envOneLine
496+ return $ if oneline then "<br>" else "<br>" <> cr
372497inlineToMuse Space = return space
373498inlineToMuse SoftBreak = do
374− wrapText <- gets $ writerWrapText . stOptions
375− return $ if wrapText == WrapPreserve then cr else space
499+ oneline <- asks envOneLine
500+ wrapText <- asks $ writerWrapText . envOptions
501+ return $ if not oneline && wrapText == WrapPreserve then cr else space
376502inlineToMuse (Link _ txt (src, _)) =
377503 case txt of
378504 [Str x] | escapeURI x == src ->
379505 return $ "[[" <> text (escapeLink x) <> "]]"
380− _ -> do contents <- inlineListToMuse txt
506+ _ -> do contents <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse txt
381507 return $ "[[" <> text (escapeLink src) <> "][" <> contents <> "]]"
382− where escapeLink lnk = if isImageUrl lnk then "URL:" ++ lnk else lnk
508+ where escapeLink lnk = if isImageUrl lnk then "URL:" ++ urlEscapeBrackets lnk else urlEscapeBrackets lnk
383509 -- Taken from muse-image-regexp defined in Emacs Muse file lisp/muse-regexps.el
384510 imageExtensions = [".eps", ".gif", ".jpg", ".jpeg", ".pbm", ".png", ".tiff", ".xbm", ".xpm"]
385511 isImageUrl = (`elem` imageExtensions) . takeExtension
386512inlineToMuse (Image attr alt (source,'f':'i':'g':':':title)) =
387513 inlineToMuse (Image attr alt (source,title))
388−inlineToMuse (Image attr inlines (source, title)) = do
389− opts <- gets stOptions
390− alt <- inlineListToMuse inlines
514+inlineToMuse (Image attr@(_, classes, _) inlines (source, title)) = do
515+ opts <- asks envOptions
516+ alt <- local (\env -> env { envInsideLinkDescription = True }) $ inlineListToMuse inlines
391517 let title' = if null title
392518 then if null inlines
393519 then ""
394520 else "[" <> alt <> "]"
395− else "[" <> text title <> "]"
521+ else "[" <> text (conditionalEscapeString True title) <> "]"
396522 let width = case dimension Width attr of
397523 Just (Percent x) | isEnabled Ext_amuse opts -> " " ++ show (round x :: Integer)
398524 _ -> ""
399− return $ "[[" <> text (source ++ width) <> "]" <> title' <> "]"
525+ let leftalign = if "align-left" `elem` classes
526+ then " l"
527+ else ""
528+ let rightalign = if "align-right" `elem` classes
529+ then " r"
530+ else ""
531+ return $ "[[" <> text (urlEscapeBrackets source ++ width ++ leftalign ++ rightalign) <> "]" <> title' <> "]"
400532inlineToMuse (Note contents) = do
401533 -- add to notes in state
402534 notes <- gets stNotes
403535 modify $ \st -> st { stNotes = contents:notes }
404536 let ref = show $ length notes + 1
405537 return $ "[" <> text ref <> "]"
406−inlineToMuse (Span (_,name:_,_) inlines) = do
538+inlineToMuse (Span (anchor,names,_) inlines) = do
407539 contents <- inlineListToMuse inlines
408− return $ "<class name=\"" <> text name <> "\">" <> contents <> "</class>"
409−inlineToMuse (Span _ lst) = inlineListToMuse lst
540+ let anchorDoc = if null anchor
541+ then mempty
542+ else text ('#':anchor) <> space
543+ return $ anchorDoc <> (if null inlines && not (null anchor)
544+ then mempty
545+ else (if null names
546+ then "<class>"
547+ else "<class name=\"" <> text (head names) <> "\">") <> contents <> "</class>")
src/Text/Pandoc/Writers/Native.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of a 'Pandoc' document to a string representation.
3031-}
3132module Text.Pandoc.Writers.Native ( writeNative )
3233where
34+import Prelude
3335import Data.List (intersperse)
3436import Data.Text (Text)
3537import Text.Pandoc.Class (PandocMonad)
src/Text/Pandoc/Writers/ODT.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE ScopedTypeVariables #-}
23{-
34Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,6 +30,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2930Conversion of 'Pandoc' documents to ODT.
3031-}
3132module Text.Pandoc.Writers.ODT ( writeODT ) where
33+import Prelude
3234import Codec.Archive.Zip
3335import Control.Monad.Except (catchError)
3436import Control.Monad.State.Strict
src/Text/Pandoc/Writers/OOXML.hs+2−1
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2012-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -39,13 +40,13 @@ module Text.Pandoc.Writers.OOXML ( mknode
3940 , fitToPage
4041 ) where
4142
43+import Prelude
4244import Codec.Archive.Zip
4345import Control.Monad.Reader
4446import qualified Data.ByteString as B
4547import qualified Data.ByteString.Lazy as BL
4648import qualified Data.ByteString.Lazy.Char8 as BL8
4749import Data.Maybe (mapMaybe)
48−import Data.Monoid ((<>))
4950import Text.Pandoc.Class (PandocMonad)
5051import qualified Text.Pandoc.UTF8 as UTF8
5152import Text.XML.Light as XML
src/Text/Pandoc/Writers/OPML.hs+4−7
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE CPP #-}
23{-
34Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -29,12 +30,13 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2930Conversion of 'Pandoc' documents to OPML XML.
3031-}
3132module Text.Pandoc.Writers.OPML ( writeOPML) where
33+import Prelude
3234import Control.Monad.Except (throwError)
3335import Data.Text (Text, unpack)
3436import qualified Data.Text as T
3537import qualified Text.Pandoc.Builder as B
3638import Text.Pandoc.Class (PandocMonad)
37−import Text.Pandoc.Compat.Time
39+import Data.Time
3840import Text.Pandoc.Definition
3941import Text.Pandoc.Error
4042import Text.Pandoc.Options
@@ -75,12 +77,7 @@ showDateTimeRFC822 = formatTime defaultTimeLocale "%a, %d %b %Y %X %Z"
7577
7678convertDate :: [Inline] -> String
7779convertDate ils = maybe "" showDateTimeRFC822 $
78−#if MIN_VERSION_time(1,5,0)
79− parseTimeM True
80−#else
81− parseTime
82−#endif
83− defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
80+ parseTimeM True defaultTimeLocale "%F" =<< normalizeDate (stringify ils)
8481
8582-- | Convert an Element to OPML.
8683elementToOPML :: PandocMonad m => WriterOptions -> Element -> m Doc
src/Text/Pandoc/Writers/OpenDocument.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleContexts #-}
23{-# LANGUAGE OverloadedStrings #-}
34{-# LANGUAGE PatternGuards #-}
@@ -32,6 +33,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3233Conversion of 'Pandoc' documents to OpenDocument XML.
3334-}
3435module Text.Pandoc.Writers.OpenDocument ( writeOpenDocument ) where
36+import Prelude
3537import Control.Arrow ((***), (>>>))
3638import Control.Monad.State.Strict hiding (when)
3739import Data.Char (chr)
src/Text/Pandoc/Writers/Org.hs+4−2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2010-2015 Puneeth Chaganti <punchagan@gmail.com>
@@ -35,6 +36,7 @@ Conversion of 'Pandoc' documents to Emacs Org-Mode.
3536Org-Mode: <http://orgmode.org>
3637-}
3738module Text.Pandoc.Writers.Org (writeOrg) where
39+import Prelude
3840import Control.Monad.State.Strict
3941import Data.Char (isAlphaNum, toLower)
4042import Data.List (intersect, intersperse, isPrefixOf, partition, transpose)
@@ -166,8 +168,8 @@ blockToOrg (LineBlock lns) = do
166168 (l, _:r) -> l : splitStanza r
167169 let joinWithLinefeeds = nowrap . mconcat . intersperse cr
168170 let joinWithBlankLines = mconcat . intersperse blankline
169− let prettyfyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
170− contents <- joinWithBlankLines <$> mapM prettyfyStanza (splitStanza lns)
171+ let prettifyStanza ls = joinWithLinefeeds <$> mapM inlineListToOrg ls
172+ contents <- joinWithBlankLines <$> mapM prettifyStanza (splitStanza lns)
171173 return $ blankline $$ "#+BEGIN_VERSE" $$
172174 nest 2 contents $$ "#+END_VERSE" <> blankline
173175blockToOrg (RawBlock "html" str) =
src/Text/Pandoc/Writers/Powerpoint.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12
23
34{-
@@ -41,6 +42,7 @@ This is a wrapper around two modules:
4142
4243module Text.Pandoc.Writers.Powerpoint (writePowerpoint) where
4344
45+import Prelude
4446import Codec.Archive.Zip
4547import Text.Pandoc.Definition
4648import Text.Pandoc.Walk
src/Text/Pandoc/Writers/Powerpoint/Output.hs+95−92
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE PatternGuards #-}
23
34{-
@@ -34,6 +35,7 @@ Text.Pandoc.Writers.Powerpoint.Presentation) to a zip archive.
3435module Text.Pandoc.Writers.Powerpoint.Output ( presentationToArchive
3536 ) where
3637
38+import Prelude
3739import Control.Monad.Except (throwError, catchError)
3840import Control.Monad.Reader
3941import Control.Monad.State
@@ -41,7 +43,7 @@ import Codec.Archive.Zip
4143import Data.Char (toUpper)
4244import Data.List (intercalate, stripPrefix, nub, union, isPrefixOf, intersperse)
4345import Data.Default
44−import Text.Pandoc.Compat.Time (formatTime, defaultTimeLocale)
46+import Data.Time (formatTime, defaultTimeLocale)
4547import Data.Time.Clock (UTCTime)
4648import Data.Time.Clock.POSIX (utcTimeToPOSIXSeconds, posixSecondsToUTCTime)
4749import System.FilePath.Posix (splitDirectories, splitExtension, takeExtension)
@@ -56,7 +58,7 @@ import Text.Pandoc.MIME
5658import qualified Data.ByteString.Lazy as BL
5759import Text.Pandoc.Writers.OOXML
5860import qualified Data.Map as M
59−import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, isJust, maybeToList, catMaybes)
61+import Data.Maybe (mapMaybe, listToMaybe, fromMaybe, maybeToList, catMaybes)
6062import Text.Pandoc.ImageSize
6163import Control.Applicative ((<|>))
6264import System.FilePath.Glob
@@ -281,8 +283,9 @@ makeSlideIdMap (Presentation _ slides) =
281283makeSpeakerNotesMap :: Presentation -> M.Map Int Int
282284makeSpeakerNotesMap (Presentation _ slides) =
283285 M.fromList $ (mapMaybe f $ slides `zip` [1..]) `zip` [1..]
284− where f (Slide _ _ Nothing, _) = Nothing
285− f (Slide _ _ (Just _), n) = Just n
286+ where f (Slide _ _ notes, n) = if notes == mempty
287+ then Nothing
288+ else Just n
286289
287290presentationToArchive :: PandocMonad m => WriterOptions -> Presentation -> m Archive
288291presentationToArchive opts pres = do
@@ -322,13 +325,11 @@ presentationToArchive opts pres = do
322325-- Check to see if the presentation has speaker notes. This will
323326-- influence whether we import the notesMaster template.
324327presHasSpeakerNotes :: Presentation -> Bool
325−presHasSpeakerNotes (Presentation _ slides) = any isJust $ map slideSpeakerNotes slides
328+presHasSpeakerNotes (Presentation _ slides) = not $ all (mempty ==) $ map slideSpeakerNotes slides
326329
327330curSlideHasSpeakerNotes :: PandocMonad m => P m Bool
328−curSlideHasSpeakerNotes = do
329− sldId <- asks envCurSlideId
330− notesIdMap <- asks envSpeakerNotesIdMap
331− return $ isJust $ M.lookup sldId notesIdMap
331+curSlideHasSpeakerNotes =
332+ M.member <$> asks envCurSlideId <*> asks envSpeakerNotesIdMap
332333
333334--------------------------------------------------
334335
@@ -339,17 +340,9 @@ getLayout layout = do
339340 (TitleSlide _) -> "ppt/slideLayouts/slideLayout3.xml"
340341 (ContentSlide _ _) -> "ppt/slideLayouts/slideLayout2.xml"
341342 (TwoColumnSlide _ _ _) -> "ppt/slideLayouts/slideLayout4.xml"
343+ refArchive <- asks envRefArchive
342344 distArchive <- asks envDistArchive
343− root <- case findEntryByPath layoutpath distArchive of
344− Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
345− Just element -> return $ element
346− Nothing -> throwError $
347− PandocSomeError $
348− layoutpath ++ " corrupt in reference file"
349− Nothing -> throwError $
350− PandocSomeError $
351− layoutpath ++ " missing in reference file"
352− return root
345+ parseXml refArchive distArchive layoutpath
353346
354347shapeHasId :: NameSpaces -> String -> Element -> Bool
355348shapeHasId ns ident element
@@ -930,6 +923,13 @@ graphicFrameToElements layout tbls caption = do
930923 return [graphicFrameElts, capElt]
931924 else return [graphicFrameElts]
932925
926+getDefaultTableStyle :: PandocMonad m => P m (Maybe String)
927+getDefaultTableStyle = do
928+ refArchive <- asks envRefArchive
929+ distArchive <- asks envDistArchive
930+ tblStyleLst <- parseXml refArchive distArchive "ppt/tableStyles.xml"
931+ return $ findAttr (QName "def" Nothing Nothing) tblStyleLst
932+
933933graphicToElement :: PandocMonad m => Integer -> Graphic -> P m Element
934934graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
935935 let colWidths = if null hdrCells
@@ -967,12 +967,19 @@ graphicToElement tableWidth (Tbl tblPr hdrCells rows) = do
967967 let mkgridcol w = mknode "a:gridCol"
968968 [("w", show ((12700 * w) :: Integer))] ()
969969 let hasHeader = not (all null hdrCells)
970+
971+ mbDefTblStyle <- getDefaultTableStyle
972+ let tblPrElt = mknode "a:tblPr"
973+ [ ("firstRow", if tblPrFirstRow tblPr then "1" else "0")
974+ , ("bandRow", if tblPrBandRow tblPr then "1" else "0")
975+ ] (case mbDefTblStyle of
976+ Nothing -> []
977+ Just sty -> [mknode "a:tableStyleId" [] sty])
978+
970979 return $ mknode "a:graphic" [] $
971980 [mknode "a:graphicData" [("uri", "http://schemas.openxmlformats.org/drawingml/2006/table")] $
972981 [mknode "a:tbl" [] $
973− [ mknode "a:tblPr" [ ("firstRow", if tblPrFirstRow tblPr then "1" else "0")
974− , ("bandRow", if tblPrBandRow tblPr then "1" else "0")
975− ] ()
982+ [ tblPrElt
976983 , mknode "a:tblGrid" [] (if all (==0) colWidths
977984 then []
978985 else map mkgridcol colWidths)
@@ -994,6 +1001,14 @@ getShapeByPlaceHolderType ns spTreeElem phType
9941001 filterChild findPhType spTreeElem
9951002 | otherwise = Nothing
9961003
1004+-- Like the above, but it tries a number of different placeholder types
1005+getShapeByPlaceHolderTypes :: NameSpaces -> Element -> [String] -> Maybe Element
1006+getShapeByPlaceHolderTypes _ _ [] = Nothing
1007+getShapeByPlaceHolderTypes ns spTreeElem (s:ss) =
1008+ case getShapeByPlaceHolderType ns spTreeElem s of
1009+ Just element -> Just element
1010+ Nothing -> getShapeByPlaceHolderTypes ns spTreeElem ss
1011+
9971012getShapeByPlaceHolderIndex :: NameSpaces -> Element -> String -> Maybe Element
9981013getShapeByPlaceHolderIndex ns spTreeElem phIdx
9991014 | isElem ns "p" "spTree" spTreeElem =
@@ -1008,12 +1023,12 @@ getShapeByPlaceHolderIndex ns spTreeElem phIdx
10081023 | otherwise = Nothing
10091024
10101025
1011−nonBodyTextToElement :: PandocMonad m => Element -> String -> [ParaElem] -> P m Element
1012−nonBodyTextToElement layout phType paraElements
1026+nonBodyTextToElement :: PandocMonad m => Element -> [String] -> [ParaElem] -> P m Element
1027+nonBodyTextToElement layout phTypes paraElements
10131028 | ns <- elemToNameSpaces layout
10141029 , Just cSld <- findChild (elemName ns "p" "cSld") layout
10151030 , Just spTree <- findChild (elemName ns "p" "spTree") cSld
1016− , Just sp <- getShapeByPlaceHolderType ns spTree phType = do
1031+ , Just sp <- getShapeByPlaceHolderTypes ns spTree phTypes = do
10171032 let hdrPara = Paragraph def paraElements
10181033 element <- paragraphToElement hdrPara
10191034 let txBody = mknode "p:txBody" [] $
@@ -1028,7 +1043,7 @@ contentToElement layout hdrShape shapes
10281043 | ns <- elemToNameSpaces layout
10291044 , Just cSld <- findChild (elemName ns "p" "cSld") layout
10301045 , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
1031− element <- nonBodyTextToElement layout "title" hdrShape
1046+ element <- nonBodyTextToElement layout ["title"] hdrShape
10321047 let hdrShapeElements = if null hdrShape
10331048 then []
10341049 else [element]
@@ -1046,7 +1061,7 @@ twoColumnToElement layout hdrShape shapesL shapesR
10461061 | ns <- elemToNameSpaces layout
10471062 , Just cSld <- findChild (elemName ns "p" "cSld") layout
10481063 , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
1049− element <- nonBodyTextToElement layout "title" hdrShape
1064+ element <- nonBodyTextToElement layout ["title"] hdrShape
10501065 let hdrShapeElements = if null hdrShape
10511066 then []
10521067 else [element]
@@ -1070,7 +1085,7 @@ titleToElement layout titleElems
10701085 | ns <- elemToNameSpaces layout
10711086 , Just cSld <- findChild (elemName ns "p" "cSld") layout
10721087 , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
1073− element <- nonBodyTextToElement layout "title" titleElems
1088+ element <- nonBodyTextToElement layout ["title", "ctrTitle"] titleElems
10741089 let titleShapeElements = if null titleElems
10751090 then []
10761091 else [element]
@@ -1084,15 +1099,15 @@ metadataToElement layout titleElems subtitleElems authorsElems dateElems
10841099 , Just spTree <- findChild (elemName ns "p" "spTree") cSld = do
10851100 titleShapeElements <- if null titleElems
10861101 then return []
1087− else sequence [nonBodyTextToElement layout "ctrTitle" titleElems]
1102+ else sequence [nonBodyTextToElement layout ["ctrTitle"] titleElems]
10881103 let combinedAuthorElems = intercalate [Break] authorsElems
10891104 subtitleAndAuthorElems = intercalate [Break, Break] [subtitleElems, combinedAuthorElems]
10901105 subtitleShapeElements <- if null subtitleAndAuthorElems
10911106 then return []
1092− else sequence [nonBodyTextToElement layout "subTitle" subtitleAndAuthorElems]
1107+ else sequence [nonBodyTextToElement layout ["subTitle"] subtitleAndAuthorElems]
10931108 dateShapeElements <- if null dateElems
10941109 then return []
1095− else sequence [nonBodyTextToElement layout "dt" dateElems]
1110+ else sequence [nonBodyTextToElement layout ["dt"] dateElems]
10961111 return $ replaceNamedChildren ns "p" "sp"
10971112 (titleShapeElements ++ subtitleShapeElements ++ dateShapeElements)
10981113 spTree
@@ -1144,18 +1159,9 @@ slideToElement (Slide _ l@(MetadataSlide titleElems subtitleElems authorElems da
11441159
11451160getNotesMaster :: PandocMonad m => P m Element
11461161getNotesMaster = do
1147− let notesMasterPath = "ppt/notesMasters/notesMaster1.xml"
1162+ refArchive <- asks envRefArchive
11481163 distArchive <- asks envDistArchive
1149− root <- case findEntryByPath notesMasterPath distArchive of
1150− Just e -> case parseXMLDoc $ UTF8.toStringLazy $ fromEntry e of
1151− Just element -> return $ element
1152− Nothing -> throwError $
1153− PandocSomeError $
1154− notesMasterPath ++ " corrupt in reference file"
1155− Nothing -> throwError $
1156− PandocSomeError $
1157− notesMasterPath ++ " missing in reference file"
1158− return root
1164+ parseXml refArchive distArchive "ppt/notesMasters/notesMaster1.xml"
11591165
11601166getSlideNumberFieldId :: PandocMonad m => Element -> P m String
11611167getSlideNumberFieldId notesMaster
@@ -1256,42 +1262,40 @@ speakerNotesSlideNumber pgNum fieldId =
12561262 ]
12571263
12581264slideToSpeakerNotesElement :: PandocMonad m => Slide -> P m (Maybe Element)
1259−slideToSpeakerNotesElement slide
1260− | Slide _ _ mbNotes <- slide
1261− , Just (SpeakerNotes paras) <- mbNotes = do
1262− master <- getNotesMaster
1263− fieldId <- getSlideNumberFieldId master
1264− num <- slideNum slide
1265− let imgShape = speakerNotesSlideImage
1266− sldNumShape = speakerNotesSlideNumber num fieldId
1267− bodyShape <- speakerNotesBody paras
1268− return $ Just $
1269− mknode "p:notes"
1270− [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main")
1271− , ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
1272− , ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
1273− ] [ mknode "p:cSld" []
1274− [ mknode "p:spTree" []
1275− [ mknode "p:nvGrpSpPr" []
1276− [ mknode "p:cNvPr" [("id", "1"), ("name", "")] ()
1277− , mknode "p:cNvGrpSpPr" [] ()
1278− , mknode "p:nvPr" [] ()
1279− ]
1280− , mknode "p:grpSpPr" []
1281− [ mknode "a:xfrm" []
1282− [ mknode "a:off" [("x", "0"), ("y", "0")] ()
1283− , mknode "a:ext" [("cx", "0"), ("cy", "0")] ()
1284− , mknode "a:chOff" [("x", "0"), ("y", "0")] ()
1285− , mknode "a:chExt" [("cx", "0"), ("cy", "0")] ()
1286− ]
1287− ]
1288− , imgShape
1289− , bodyShape
1290− , sldNumShape
1265+slideToSpeakerNotesElement (Slide _ _ (SpeakerNotes [])) = return Nothing
1266+slideToSpeakerNotesElement slide@(Slide _ _ (SpeakerNotes paras)) = do
1267+ master <- getNotesMaster
1268+ fieldId <- getSlideNumberFieldId master
1269+ num <- slideNum slide
1270+ let imgShape = speakerNotesSlideImage
1271+ sldNumShape = speakerNotesSlideNumber num fieldId
1272+ bodyShape <- speakerNotesBody paras
1273+ return $ Just $
1274+ mknode "p:notes"
1275+ [ ("xmlns:a", "http://schemas.openxmlformats.org/drawingml/2006/main")
1276+ , ("xmlns:r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships")
1277+ , ("xmlns:p", "http://schemas.openxmlformats.org/presentationml/2006/main")
1278+ ] [ mknode "p:cSld" []
1279+ [ mknode "p:spTree" []
1280+ [ mknode "p:nvGrpSpPr" []
1281+ [ mknode "p:cNvPr" [("id", "1"), ("name", "")] ()
1282+ , mknode "p:cNvGrpSpPr" [] ()
1283+ , mknode "p:nvPr" [] ()
12911284 ]
1285+ , mknode "p:grpSpPr" []
1286+ [ mknode "a:xfrm" []
1287+ [ mknode "a:off" [("x", "0"), ("y", "0")] ()
1288+ , mknode "a:ext" [("cx", "0"), ("cy", "0")] ()
1289+ , mknode "a:chOff" [("x", "0"), ("y", "0")] ()
1290+ , mknode "a:chExt" [("cx", "0"), ("cy", "0")] ()
1291+ ]
12921292 ]
1293+ , imgShape
1294+ , bodyShape
1295+ , sldNumShape
12931296 ]
1294−slideToSpeakerNotesElement _ = return Nothing
1297+ ]
1298+ ]
12951299
12961300-----------------------------------------------------------------------
12971301
@@ -1466,23 +1470,22 @@ slideToSpeakerNotesEntry slide = do
14661470 _ -> return Nothing
14671471
14681472slideToSpeakerNotesRelElement :: PandocMonad m => Slide -> P m (Maybe Element)
1469−slideToSpeakerNotesRelElement slide
1470− | Slide _ _ mbNotes <- slide
1471− , Just _ <- mbNotes = do
1472− idNum <- slideNum slide
1473− return $ Just $
1474− mknode "Relationships"
1475− [("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
1476− [ mknode "Relationship" [ ("Id", "rId2")
1477− , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
1478− , ("Target", "../slides/slide" ++ show idNum ++ ".xml")
1479− ] ()
1480− , mknode "Relationship" [ ("Id", "rId1")
1481− , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
1482− , ("Target", "../notesMasters/notesMaster1.xml")
1483− ] ()
1484− ]
1485−slideToSpeakerNotesRelElement _ = return Nothing
1473+slideToSpeakerNotesRelElement (Slide _ _ (SpeakerNotes [])) = return Nothing
1474+slideToSpeakerNotesRelElement slide@(Slide _ _ _) = do
1475+ idNum <- slideNum slide
1476+ return $ Just $
1477+ mknode "Relationships"
1478+ [("xmlns", "http://schemas.openxmlformats.org/package/2006/relationships")]
1479+ [ mknode "Relationship" [ ("Id", "rId2")
1480+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/slide")
1481+ , ("Target", "../slides/slide" ++ show idNum ++ ".xml")
1482+ ] ()
1483+ , mknode "Relationship" [ ("Id", "rId1")
1484+ , ("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/notesMaster")
1485+ , ("Target", "../notesMasters/notesMaster1.xml")
1486+ ] ()
1487+ ]
1488+
14861489
14871490slideToSpeakerNotesRelEntry :: PandocMonad m => Slide -> P m (Maybe Entry)
14881491slideToSpeakerNotesRelEntry slide = do
src/Text/Pandoc/Writers/Powerpoint/Presentation.hs+132−97
@@ -1,4 +1,6 @@
1−{-# LANGUAGE PatternGuards #-}
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE PatternGuards #-}
3+{-# LANGUAGE GeneralizedNewtypeDeriving #-}
24
35{-
46Copyright (C) 2017-2018 Jesse Rosenthal <jrosenthal@jhu.edu>
@@ -57,6 +59,7 @@ module Text.Pandoc.Writers.Powerpoint.Presentation ( documentToPresentation
5759 ) where
5860
5961
62+import Prelude
6063import Control.Monad.Reader
6164import Control.Monad.State
6265import Data.List (intercalate)
@@ -67,7 +70,7 @@ import Text.Pandoc.Slides (getSlideLevel)
6770import Text.Pandoc.Options
6871import Text.Pandoc.Logging
6972import Text.Pandoc.Walk
70−import Text.Pandoc.Compat.Time (UTCTime)
73+import Data.Time (UTCTime)
7174import qualified Text.Pandoc.Shared as Shared -- so we don't overlap "Element"
7275import Text.Pandoc.Writers.Shared (metaValueToInlines)
7376import qualified Data.Map as M
@@ -110,7 +113,7 @@ data WriterState = WriterState { stNoteIds :: M.Map Int [Block]
110113 , stAnchorMap :: M.Map String SlideId
111114 , stSlideIdSet :: S.Set SlideId
112115 , stLog :: [LogMessage]
113− , stSpeakerNotesMap :: M.Map SlideId [[Paragraph]]
116+ , stSpeakerNotes :: SpeakerNotes
114117 } deriving (Show, Eq)
115118
116119instance Default WriterState where
@@ -119,7 +122,7 @@ instance Default WriterState where
119122 -- we reserve this s
120123 , stSlideIdSet = reservedSlideIds
121124 , stLog = []
122− , stSpeakerNotesMap = mempty
125+ , stSpeakerNotes = mempty
123126 }
124127
125128metadataSlideId :: SlideId
@@ -183,7 +186,7 @@ data DocProps = DocProps { dcTitle :: Maybe String
183186
184187data Slide = Slide { slideId :: SlideId
185188 , slideLayout :: Layout
186− , slideSpeakerNotes :: Maybe SpeakerNotes
189+ , slideSpeakerNotes :: SpeakerNotes
187190 } deriving (Show, Eq)
188191
189192newtype SlideId = SlideId String
@@ -193,7 +196,7 @@ newtype SlideId = SlideId String
193196-- designed mainly for one textbox, so we'll just put in the contents
194197-- of that textbox, to avoid other shapes that won't work as well.
195198newtype SpeakerNotes = SpeakerNotes {fromSpeakerNotes :: [Paragraph]}
196− deriving (Show, Eq)
199+ deriving (Show, Eq, Monoid, Semigroup)
197200
198201data Layout = MetadataSlide { metadataSlideTitle :: [ParaElem]
199202 , metadataSlideSubtitle :: [ParaElem]
@@ -229,7 +232,6 @@ data Paragraph = Paragraph { paraProps :: ParaProps
229232 , paraElems :: [ParaElem]
230233 } deriving (Show, Eq)
231234
232−
233235data BulletType = Bullet
234236 | AutoNumbering ListAttributes
235237 deriving (Show, Eq)
@@ -374,9 +376,20 @@ inlineToParElems (Note blks) = do
374376 modify $ \st -> st { stNoteIds = M.insert curNoteId blks notes }
375377 local (\env -> env{envRunProps = (envRunProps env){rLink = Just $ InternalTarget endNotesSlideId}}) $
376378 inlineToParElems $ Superscript [Str $ show curNoteId]
377−inlineToParElems (Span _ ils) = concatMapM inlineToParElems ils
379+inlineToParElems (Span _ ils) = inlinesToParElems ils
380+inlineToParElems (Quoted quoteType ils) =
381+ inlinesToParElems $ [Str open] ++ ils ++ [Str close]
382+ where (open, close) = case quoteType of
383+ SingleQuote -> ("\x2018", "\x2019")
384+ DoubleQuote -> ("\x201C", "\x201D")
378385inlineToParElems (RawInline _ _) = return []
379−inlineToParElems _ = return []
386+inlineToParElems (Cite _ ils) = inlinesToParElems ils
387+-- Note: we shouldn't reach this, because images should be handled at
388+-- the shape level, but should that change in the future, we render
389+-- the alt text.
390+inlineToParElems (Image _ alt _) = inlinesToParElems alt
391+
392+
380393
381394isListType :: Block -> Bool
382395isListType (OrderedList _ _) = True
@@ -399,10 +412,7 @@ noteSize :: Pixels
399412noteSize = 18
400413
401414blockToParagraphs :: Block -> Pres [Paragraph]
402−blockToParagraphs (Plain ils) = do
403− parElems <- inlinesToParElems ils
404− pProps <- asks envParaProps
405− return [Paragraph pProps parElems]
415+blockToParagraphs (Plain ils) = blockToParagraphs (Para ils)
406416blockToParagraphs (Para ils) = do
407417 parElems <- inlinesToParElems ils
408418 pProps <- asks envParaProps
@@ -475,16 +485,6 @@ blockToParagraphs (DefinitionList entries) = do
475485 definition <- concatMapM (blockToParagraphs . BlockQuote) blksLst
476486 return $ term ++ definition
477487 concatMapM go entries
478−blockToParagraphs (Div (_, "notes" : [], _) blks) =
479− local (\env -> env{envInSpeakerNotes=True}) $ do
480− sldId <- asks envCurSlideId
481− spkNotesMap <- gets stSpeakerNotesMap
482− paras <- concatMapM blockToParagraphs blks
483− let spkNotesMap' = case M.lookup sldId spkNotesMap of
484− Just lst -> M.insert sldId (paras : lst) spkNotesMap
485− Nothing -> M.insert sldId [paras] spkNotesMap
486− modify $ \st -> st{stSpeakerNotesMap = spkNotesMap'}
487− return []
488488blockToParagraphs (Div _ blks) = concatMapM blockToParagraphs blks
489489blockToParagraphs blk = do
490490 addLogMessage $ BlockNotRendered blk
@@ -527,14 +527,9 @@ withAttr attr (Pic picPr url caption) =
527527withAttr _ sp = sp
528528
529529blockToShape :: Block -> Pres Shape
530−blockToShape (Plain (il:_)) | Image attr ils (url, _) <- il =
531− (withAttr attr . Pic def url) <$> inlinesToParElems ils
530+blockToShape (Plain ils) = blockToShape (Para ils)
532531blockToShape (Para (il:_)) | Image attr ils (url, _) <- il =
533532 (withAttr attr . Pic def url) <$> inlinesToParElems ils
534−blockToShape (Plain (il:_)) | Link _ (il':_) target <- il
535− , Image attr ils (url, _) <- il' =
536− (withAttr attr . Pic def {picPropLink = Just $ ExternalTarget target} url) <$>
537− inlinesToParElems ils
538533blockToShape (Para (il:_)) | Link _ (il':_) target <- il
539534 , Image attr ils (url, _) <- il' =
540535 (withAttr attr . Pic def{picPropLink = Just $ ExternalTarget target} url) <$>
@@ -558,20 +553,23 @@ blockToShape blk = do paras <- blockToParagraphs blk
558553
559554combineShapes :: [Shape] -> [Shape]
560555combineShapes [] = []
561−combineShapes[s] = [s]
562−combineShapes (pic@(Pic{}) : ss) = pic : combineShapes ss
556+combineShapes (pic@Pic{} : ss) = pic : combineShapes ss
563557combineShapes (TextBox [] : ss) = combineShapes ss
564558combineShapes (s : TextBox [] : ss) = combineShapes (s : ss)
565559combineShapes (TextBox (p:ps) : TextBox (p':ps') : ss) =
566560 combineShapes $ TextBox ((p:ps) ++ (p':ps')) : ss
567561combineShapes (s:ss) = s : combineShapes ss
568562
563+isNotesDiv :: Block -> Bool
564+isNotesDiv (Div (_, ["notes"], _) _) = True
565+isNotesDiv _ = False
566+
569567blocksToShapes :: [Block] -> Pres [Shape]
570568blocksToShapes blks = combineShapes <$> mapM blockToShape blks
571569
572570isImage :: Inline -> Bool
573−isImage (Image{}) = True
574−isImage (Link _ (Image _ _ _ : _) _) = True
571+isImage Image{} = True
572+isImage (Link _ (Image{} : _) _) = True
575573isImage _ = False
576574
577575splitBlocks' :: [Block] -> [[Block]] -> [Block] -> Pres [[Block]]
@@ -589,64 +587,60 @@ splitBlocks' cur acc (h@(Header n _ _) : blks) = do
589587splitBlocks' cur acc (Plain ils : blks) = splitBlocks' cur acc (Para ils : blks)
590588splitBlocks' cur acc (Para (il:ils) : blks) | isImage il = do
591589 slideLevel <- asks envSlideLevel
590+ let (nts, blks') = if null ils
591+ then span isNotesDiv blks
592+ else ([], blks)
592593 case cur of
593− [(Header n _ _)] | n == slideLevel ->
594+ [Header n _ _] | n == slideLevel ->
594595 splitBlocks' []
595− (acc ++ [cur ++ [Para [il]]])
596− (if null ils then blks else Para ils : blks)
596+ (acc ++ [cur ++ [Para [il]] ++ nts])
597+ (if null ils then blks' else Para ils : blks')
597598 _ -> splitBlocks' []
598− (acc ++ (if null cur then [] else [cur]) ++ [[Para [il]]])
599− (if null ils then blks else Para ils : blks)
600−splitBlocks' cur acc (tbl@(Table{}) : blks) = do
599+ (acc ++ (if null cur then [] else [cur]) ++ [[Para [il]] ++ nts])
600+ (if null ils then blks' else Para ils : blks')
601+splitBlocks' cur acc (tbl@Table{} : blks) = do
601602 slideLevel <- asks envSlideLevel
603+ let (nts, blks') = span isNotesDiv blks
602604 case cur of
603− [(Header n _ _)] | n == slideLevel ->
604− splitBlocks' [] (acc ++ [cur ++ [tbl]]) blks
605− _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[tbl]]) blks
605+ [Header n _ _] | n == slideLevel ->
606+ splitBlocks' [] (acc ++ [cur ++ [tbl] ++ nts]) blks'
607+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[tbl] ++ nts]) blks'
606608splitBlocks' cur acc (d@(Div (_, classes, _) _): blks) | "columns" `elem` classes = do
607609 slideLevel <- asks envSlideLevel
610+ let (nts, blks') = span isNotesDiv blks
608611 case cur of
609− [(Header n _ _)] | n == slideLevel ->
610− splitBlocks' [] (acc ++ [cur ++ [d]]) blks
611− _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[d]]) blks
612+ [Header n _ _] | n == slideLevel ->
613+ splitBlocks' [] (acc ++ [cur ++ [d] ++ nts]) blks'
614+ _ -> splitBlocks' [] (acc ++ (if null cur then [] else [cur]) ++ [[d] ++ nts]) blks'
612615splitBlocks' cur acc (blk : blks) = splitBlocks' (cur ++ [blk]) acc blks
613616
614617splitBlocks :: [Block] -> Pres [[Block]]
615618splitBlocks = splitBlocks' [] []
616619
617−getSpeakerNotes :: Pres (Maybe SpeakerNotes)
618−getSpeakerNotes = do
619− sldId <- asks envCurSlideId
620− spkNtsMap <- gets stSpeakerNotesMap
621− return $ (SpeakerNotes . concat . reverse) <$> (M.lookup sldId spkNtsMap)
622−
623−blocksToSlide' :: Int -> [Block] -> Pres Slide
624−blocksToSlide' lvl (Header n (ident, _, _) ils : blks)
620+blocksToSlide' :: Int -> [Block] -> SpeakerNotes -> Pres Slide
621+blocksToSlide' lvl (Header n (ident, _, _) ils : blks) spkNotes
625622 | n < lvl = do
626623 registerAnchorId ident
627624 sldId <- asks envCurSlideId
628625 hdr <- inlinesToParElems ils
629− return $ Slide sldId TitleSlide {titleSlideHeader = hdr} Nothing
626+ return $ Slide sldId TitleSlide {titleSlideHeader = hdr} spkNotes
630627 | n == lvl = do
631628 registerAnchorId ident
632629 hdr <- inlinesToParElems ils
633630 -- Now get the slide without the header, and then add the header
634631 -- in.
635− slide <- blocksToSlide' lvl blks
632+ slide <- blocksToSlide' lvl blks spkNotes
636633 let layout = case slideLayout slide of
637634 ContentSlide _ cont -> ContentSlide hdr cont
638635 TwoColumnSlide _ contL contR -> TwoColumnSlide hdr contL contR
639636 layout' -> layout'
640637 return $ slide{slideLayout = layout}
641−blocksToSlide' _ (blk : blks)
638+blocksToSlide' _ (blk : blks) spkNotes
642639 | Div (_, classes, _) divBlks <- blk
643640 , "columns" `elem` classes
644641 , Div (_, clsL, _) blksL : Div (_, clsR, _) blksR : remaining <- divBlks
645642 , "column" `elem` clsL, "column" `elem` clsR = do
646− unless (null blks)
647− (mapM (addLogMessage . BlockNotRendered) blks >> return ())
648− unless (null remaining)
649− (mapM (addLogMessage . BlockNotRendered) remaining >> return ())
643+ mapM_ (addLogMessage . BlockNotRendered) (blks ++ remaining)
650644 mbSplitBlksL <- splitBlocks blksL
651645 mbSplitBlksR <- splitBlocks blksR
652646 let blksL' = case mbSplitBlksL of
@@ -664,8 +658,8 @@ blocksToSlide' _ (blk : blks)
664658 , twoColumnSlideLeft = shapesL
665659 , twoColumnSlideRight = shapesR
666660 }
667− Nothing
668−blocksToSlide' _ (blk : blks) = do
661+ spkNotes
662+blocksToSlide' _ (blk : blks) spkNotes = do
669663 inNoteSlide <- asks envInNoteSlide
670664 shapes <- if inNoteSlide
671665 then forceFontSize noteSize $ blocksToShapes (blk : blks)
@@ -677,8 +671,8 @@ blocksToSlide' _ (blk : blks) = do
677671 ContentSlide { contentSlideHeader = []
678672 , contentSlideContent = shapes
679673 }
680− Nothing
681−blocksToSlide' _ [] = do
674+ spkNotes
675+blocksToSlide' _ [] spkNotes = do
682676 sldId <- asks envCurSlideId
683677 return $
684678 Slide
@@ -686,14 +680,32 @@ blocksToSlide' _ [] = do
686680 ContentSlide { contentSlideHeader = []
687681 , contentSlideContent = []
688682 }
689− Nothing
683+ spkNotes
684+
685+handleNotes :: Block -> Pres ()
686+handleNotes (Div (_, ["notes"], _) blks) =
687+ local (\env -> env{envInSpeakerNotes=True}) $ do
688+ spNotes <- SpeakerNotes <$> concatMapM blockToParagraphs blks
689+ modify $ \st -> st{stSpeakerNotes = (stSpeakerNotes st) <> spNotes}
690+handleNotes _ = return ()
691+
692+handleAndFilterNotes' :: [Block] -> Pres [Block]
693+handleAndFilterNotes' blks = do
694+ mapM_ handleNotes blks
695+ return $ filter (not . isNotesDiv) blks
696+
697+handleAndFilterNotes :: [Block] -> Pres ([Block], SpeakerNotes)
698+handleAndFilterNotes blks = do
699+ modify $ \st -> st{stSpeakerNotes = mempty}
700+ blks' <- walkM handleAndFilterNotes' blks
701+ spkNotes <- gets stSpeakerNotes
702+ return (blks', spkNotes)
690703
691704blocksToSlide :: [Block] -> Pres Slide
692705blocksToSlide blks = do
706+ (blks', spkNotes) <- handleAndFilterNotes blks
693707 slideLevel <- asks envSlideLevel
694− sld <- blocksToSlide' slideLevel blks
695− spkNotes <- getSpeakerNotes
696− return $ sld{slideSpeakerNotes = spkNotes}
708+ blocksToSlide' slideLevel blks' spkNotes
697709
698710makeNoteEntry :: Int -> [Block] -> [Block]
699711makeNoteEntry n blks =
@@ -719,15 +731,14 @@ makeEndNotesSlideBlocks = do
719731 anchorSet <- M.keysSet <$> gets stAnchorMap
720732 if M.null noteIds
721733 then return []
722− else do let title = case lookupMeta "notes-title" meta of
723− Just val -> metaValueToInlines val
724− Nothing -> [Str "Notes"]
725− ident = Shared.uniqueIdent title anchorSet
726− hdr = Header slideLevel (ident, [], []) title
727− blks <- return $
728− concatMap (\(n, bs) -> makeNoteEntry n bs) $
734+ else let title = case lookupMeta "notes-title" meta of
735+ Just val -> metaValueToInlines val
736+ Nothing -> [Str "Notes"]
737+ ident = Shared.uniqueIdent title anchorSet
738+ hdr = Header slideLevel (ident, [], []) title
739+ blks = concatMap (\(n, bs) -> makeNoteEntry n bs) $
729740 M.toList noteIds
730− return $ hdr : blks
741+ in return $ hdr : blks
731742
732743getMetaSlide :: Pres (Maybe Slide)
733744getMetaSlide = do
@@ -753,7 +764,7 @@ getMetaSlide = do
753764 , metadataSlideAuthors = authors
754765 , metadataSlideDate = date
755766 }
756− Nothing
767+ mempty
757768
758769-- adapted from the markdown writer
759770elementToListItem :: Shared.Element -> Pres [Block]
@@ -778,8 +789,7 @@ makeTOCSlide blks = local (\env -> env{envCurSlideId = tocSlideId}) $ do
778789 Just val -> metaValueToInlines val
779790 Nothing -> [Str "Table of Contents"]
780791 hdr = Header slideLevel nullAttr tocTitle
781− sld <- blocksToSlide [hdr, contents]
782− return sld
792+ blocksToSlide [hdr, contents]
783793
784794combineParaElems' :: Maybe ParaElem -> [ParaElem] -> [ParaElem]
785795combineParaElems' mbPElem [] = maybeToList mbPElem
@@ -802,15 +812,9 @@ applyToParagraph f para = do
802812 return $ para {paraElems = paraElems'}
803813
804814applyToShape :: Monad m => (ParaElem -> m ParaElem) -> Shape -> m Shape
805−applyToShape f (Pic pPr fp pes) = do
806− pes' <- mapM f pes
807− return $ Pic pPr fp pes'
808−applyToShape f (GraphicFrame gfx pes) = do
809− pes' <- mapM f pes
810− return $ GraphicFrame gfx pes'
811−applyToShape f (TextBox paras) = do
812− paras' <- mapM (applyToParagraph f) paras
813− return $ TextBox paras'
815+applyToShape f (Pic pPr fp pes) = Pic pPr fp <$> mapM f pes
816+applyToShape f (GraphicFrame gfx pes) = GraphicFrame gfx <$> mapM f pes
817+applyToShape f (TextBox paras) = TextBox <$> mapM (applyToParagraph f) paras
814818
815819applyToLayout :: Monad m => (ParaElem -> m ParaElem) -> Layout -> m Layout
816820applyToLayout f (MetadataSlide title subtitle authors date) = do
@@ -819,9 +823,7 @@ applyToLayout f (MetadataSlide title subtitle authors date) = do
819823 authors' <- mapM (mapM f) authors
820824 date' <- mapM f date
821825 return $ MetadataSlide title' subtitle' authors' date'
822−applyToLayout f (TitleSlide title) = do
823− title' <- mapM f title
824− return $ TitleSlide title'
826+applyToLayout f (TitleSlide title) = TitleSlide <$> mapM f title
825827applyToLayout f (ContentSlide hdr content) = do
826828 hdr' <- mapM f hdr
827829 content' <- mapM (applyToShape f) content
@@ -835,11 +837,9 @@ applyToLayout f (TwoColumnSlide hdr contentL contentR) = do
835837applyToSlide :: Monad m => (ParaElem -> m ParaElem) -> Slide -> m Slide
836838applyToSlide f slide = do
837839 layout' <- applyToLayout f $ slideLayout slide
838− mbNotes' <- case slideSpeakerNotes slide of
839− Just (SpeakerNotes notes) -> (Just . SpeakerNotes) <$>
840− mapM (applyToParagraph f) notes
841− Nothing -> return Nothing
842− return slide{slideLayout = layout', slideSpeakerNotes = mbNotes'}
840+ let paras = fromSpeakerNotes $ slideSpeakerNotes slide
841+ notes' <- SpeakerNotes <$> mapM (applyToParagraph f) paras
842+ return slide{slideLayout = layout', slideSpeakerNotes = notes'}
843843
844844replaceAnchor :: ParaElem -> Pres ParaElem
845845replaceAnchor (Run rProps s)
@@ -853,6 +853,40 @@ replaceAnchor (Run rProps s)
853853 return $ Run rProps' s
854854replaceAnchor pe = return pe
855855
856+emptyParaElem :: ParaElem -> Bool
857+emptyParaElem (Run _ s) =
858+ null $ Shared.trim s
859+emptyParaElem (MathElem _ ts) =
860+ null $ Shared.trim $ unTeXString ts
861+emptyParaElem _ = False
862+
863+emptyParagraph :: Paragraph -> Bool
864+emptyParagraph para = all emptyParaElem $ paraElems para
865+
866+
867+emptyShape :: Shape -> Bool
868+emptyShape (TextBox paras) = all emptyParagraph paras
869+emptyShape _ = False
870+
871+emptyLayout :: Layout -> Bool
872+emptyLayout layout = case layout of
873+ MetadataSlide title subtitle authors date ->
874+ all emptyParaElem title &&
875+ all emptyParaElem subtitle &&
876+ all (all emptyParaElem) authors &&
877+ all emptyParaElem date
878+ TitleSlide hdr -> all emptyParaElem hdr
879+ ContentSlide hdr shapes ->
880+ all emptyParaElem hdr &&
881+ all emptyShape shapes
882+ TwoColumnSlide hdr shapes1 shapes2 ->
883+ all emptyParaElem hdr &&
884+ all emptyShape shapes1 &&
885+ all emptyShape shapes2
886+
887+emptySlide :: Slide -> Bool
888+emptySlide (Slide _ layout notes) = (notes == mempty) && (emptyLayout layout)
889+
856890blocksToPresentationSlides :: [Block] -> Pres [Slide]
857891blocksToPresentationSlides blks = do
858892 opts <- asks envOpts
@@ -893,7 +927,8 @@ blocksToPresentationSlides blks = do
893927 return [endNotesSlide]
894928
895929 let slides = metadataslides ++ tocSlides ++ bodyslides ++ endNotesSlides
896− mapM (applyToSlide replaceAnchor) slides
930+ slides' = filter (not . emptySlide) slides
931+ mapM (applyToSlide replaceAnchor) slides'
897932
898933metaToDocProps :: Meta -> DocProps
899934metaToDocProps meta =
src/Text/Pandoc/Writers/RST.hs+119−24
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,7 +31,8 @@ Conversion of 'Pandoc' documents to reStructuredText.
3031
3132reStructuredText: <http://docutils.sourceforge.net/rst.html>
3233-}
33−module Text.Pandoc.Writers.RST ( writeRST ) where
34+module Text.Pandoc.Writers.RST ( writeRST, flatten ) where
35+import Prelude
3436import Control.Monad.State.Strict
3537import Data.Char (isSpace, toLower)
3638import Data.List (isPrefixOf, stripPrefix)
@@ -46,6 +48,7 @@ import Text.Pandoc.Pretty
4648import Text.Pandoc.Shared
4749import Text.Pandoc.Templates (renderTemplate')
4850import Text.Pandoc.Writers.Shared
51+import Text.Pandoc.Walk
4952
5053type Refs = [([Inline], Target)]
5154
@@ -260,7 +263,6 @@ blockToRST (Header level (name,classes,_) inlines) = do
260263 return $ nowrap $ hang 3 ".. " (rub $$ name' $$ cls) $$ blankline
261264blockToRST (CodeBlock (_,classes,kvs) str) = do
262265 opts <- gets stOptions
263− let tabstop = writerTabStop opts
264266 let startnum = maybe "" (\x -> " " <> text x) $ lookup "startFrom" kvs
265267 let numberlines = if "numberLines" `elem` classes
266268 then " :number-lines:" <> startnum
@@ -273,11 +275,10 @@ blockToRST (CodeBlock (_,classes,kvs) str) = do
273275 c `notElem` ["sourceCode","literate","numberLines"]] of
274276 [] -> "::"
275277 (lang:_) -> (".. code:: " <> text lang) $$ numberlines)
276− $+$ nest tabstop (text str) $$ blankline
278+ $+$ nest 3 (text str) $$ blankline
277279blockToRST (BlockQuote blocks) = do
278− tabstop <- gets $ writerTabStop . stOptions
279280 contents <- blockListToRST blocks
280− return $ nest tabstop contents <> blankline
281+ return $ nest 3 contents <> blankline
281282blockToRST (Table caption aligns widths headers rows) = do
282283 caption' <- inlineListToRST caption
283284 let blocksToDoc opts bs = do
@@ -335,8 +336,7 @@ definitionListItemToRST :: PandocMonad m => ([Inline], [[Block]]) -> RST m Doc
335336definitionListItemToRST (label, defs) = do
336337 label' <- inlineListToRST label
337338 contents <- liftM vcat $ mapM blockListToRST defs
338− tabstop <- gets $ writerTabStop . stOptions
339− return $ nowrap label' $$ nest tabstop (nestle contents <> cr)
339+ return $ nowrap label' $$ nest 3 (nestle contents <> cr)
340340
341341-- | Format a list of lines as line block.
342342linesToLineBlock :: PandocMonad m => [[Inline]] -> RST m Doc
@@ -376,12 +376,27 @@ blockListToRST :: PandocMonad m
376376 -> RST m Doc
377377blockListToRST = blockListToRST' False
378378
379−-- | Convert list of Pandoc inline elements to RST.
380−inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
381−inlineListToRST lst =
382− mapM inlineToRST (removeSpaceAfterDisplayMath $ insertBS lst) >>=
383− return . hcat
384− where -- remove spaces after displaymath, as they screw up indentation:
379+transformInlines :: [Inline] -> [Inline]
380+transformInlines = insertBS .
381+ filter hasContents .
382+ removeSpaceAfterDisplayMath .
383+ concatMap (transformNested . flatten)
384+ where -- empty inlines are not valid RST syntax
385+ hasContents :: Inline -> Bool
386+ hasContents (Str "") = False
387+ hasContents (Emph []) = False
388+ hasContents (Strong []) = False
389+ hasContents (Strikeout []) = False
390+ hasContents (Superscript []) = False
391+ hasContents (Subscript []) = False
392+ hasContents (SmallCaps []) = False
393+ hasContents (Quoted _ []) = False
394+ hasContents (Cite _ []) = False
395+ hasContents (Span _ []) = False
396+ hasContents (Link _ [] ("", "")) = False
397+ hasContents (Image _ [] ("", "")) = False
398+ hasContents _ = True
399+ -- remove spaces after displaymath, as they screw up indentation:
385400 removeSpaceAfterDisplayMath (Math DisplayMath x : zs) =
386401 Math DisplayMath x : dropWhile (==Space) zs
387402 removeSpaceAfterDisplayMath (x:xs) = x : removeSpaceAfterDisplayMath xs
@@ -399,6 +414,8 @@ inlineListToRST lst =
399414 x : insertBS (y : zs)
400415 insertBS (x:ys) = x : insertBS ys
401416 insertBS [] = []
417+ transformNested :: [Inline] -> [Inline]
418+ transformNested = map (mapNested stripLeadingTrailingSpace)
402419 surroundComplex :: Inline -> Inline -> Bool
403420 surroundComplex (Str s@(_:_)) (Str s'@(_:_)) =
404421 case (last s, head s') of
@@ -436,44 +453,122 @@ inlineListToRST lst =
436453 isComplex (Span _ (x:_)) = isComplex x
437454 isComplex _ = False
438455
456+-- | Flattens nested inlines. Extracts nested inlines and goes through
457+-- them either collapsing them in the outer inline container or
458+-- pulling them out of it
459+flatten :: Inline -> [Inline]
460+flatten outer
461+ | null contents = [outer]
462+ | otherwise = combineAll contents
463+ where contents = dropInlineParent outer
464+ combineAll = foldl combine []
465+
466+ combine :: [Inline] -> Inline -> [Inline]
467+ combine f i =
468+ case (outer, i) of
469+ -- quotes are not rendered using RST inlines, so we can keep
470+ -- them and they will be readable and parsable
471+ (Quoted _ _, _) -> keep f i
472+ (_, Quoted _ _) -> keep f i
473+ -- parent inlines would prevent links from being correctly
474+ -- parsed, in this case we prioritise the content over the
475+ -- style
476+ (_, Link _ _ _) -> emerge f i
477+ -- always give priority to strong text over emphasis
478+ (Emph _, Strong _) -> emerge f i
479+ -- drop all other nested styles
480+ (_, _) -> collapse f i
481+
482+ emerge f i = f <> [i]
483+ keep f i = appendToLast f [i]
484+ collapse f i = appendToLast f $ dropInlineParent i
485+
486+ appendToLast :: [Inline] -> [Inline] -> [Inline]
487+ appendToLast [] toAppend = [setInlineChildren outer toAppend]
488+ appendToLast flattened toAppend
489+ | isOuter lastFlat = init flattened <> [appendTo lastFlat toAppend]
490+ | otherwise = flattened <> [setInlineChildren outer toAppend]
491+ where lastFlat = last flattened
492+ appendTo o i = mapNested (<> i) o
493+ isOuter i = emptyParent i == emptyParent outer
494+ emptyParent i = setInlineChildren i []
495+
496+mapNested :: ([Inline] -> [Inline]) -> Inline -> Inline
497+mapNested f i = setInlineChildren i (f (dropInlineParent i))
498+
499+dropInlineParent :: Inline -> [Inline]
500+dropInlineParent (Link _ i _) = i
501+dropInlineParent (Emph i) = i
502+dropInlineParent (Strong i) = i
503+dropInlineParent (Strikeout i) = i
504+dropInlineParent (Superscript i) = i
505+dropInlineParent (Subscript i) = i
506+dropInlineParent (SmallCaps i) = i
507+dropInlineParent (Cite _ i) = i
508+dropInlineParent (Image _ i _) = i
509+dropInlineParent (Span _ i) = i
510+dropInlineParent (Quoted _ i) = i
511+dropInlineParent i = [i] -- not a parent, like Str or Space
512+
513+setInlineChildren :: Inline -> [Inline] -> Inline
514+setInlineChildren (Link a _ t) i = Link a i t
515+setInlineChildren (Emph _) i = Emph i
516+setInlineChildren (Strong _) i = Strong i
517+setInlineChildren (Strikeout _) i = Strikeout i
518+setInlineChildren (Superscript _) i = Superscript i
519+setInlineChildren (Subscript _) i = Subscript i
520+setInlineChildren (SmallCaps _) i = SmallCaps i
521+setInlineChildren (Quoted q _) i = Quoted q i
522+setInlineChildren (Cite c _) i = Cite c i
523+setInlineChildren (Image a _ t) i = Image a i t
524+setInlineChildren (Span a _) i = Span a i
525+setInlineChildren leaf _ = leaf
526+
527+inlineListToRST :: PandocMonad m => [Inline] -> RST m Doc
528+inlineListToRST = writeInlines . walk transformInlines
529+
530+-- | Convert list of Pandoc inline elements to RST.
531+writeInlines :: PandocMonad m => [Inline] -> RST m Doc
532+writeInlines lst = mapM inlineToRST lst >>= return . hcat
533+
439534-- | Convert Pandoc inline element to RST.
440535inlineToRST :: PandocMonad m => Inline -> RST m Doc
441536inlineToRST (Span (_,_,kvs) ils) = do
442− contents <- inlineListToRST ils
537+ contents <- writeInlines ils
443538 return $
444539 case lookup "role" kvs of
445540 Just role -> ":" <> text role <> ":`" <> contents <> "`"
446541 Nothing -> contents
447542inlineToRST (Emph lst) = do
448− contents <- inlineListToRST lst
543+ contents <- writeInlines lst
449544 return $ "*" <> contents <> "*"
450545inlineToRST (Strong lst) = do
451− contents <- inlineListToRST lst
546+ contents <- writeInlines lst
452547 return $ "**" <> contents <> "**"
453548inlineToRST (Strikeout lst) = do
454− contents <- inlineListToRST lst
549+ contents <- writeInlines lst
455550 return $ "[STRIKEOUT:" <> contents <> "]"
456551inlineToRST (Superscript lst) = do
457− contents <- inlineListToRST lst
552+ contents <- writeInlines lst
458553 return $ ":sup:`" <> contents <> "`"
459554inlineToRST (Subscript lst) = do
460− contents <- inlineListToRST lst
555+ contents <- writeInlines lst
461556 return $ ":sub:`" <> contents <> "`"
462−inlineToRST (SmallCaps lst) = inlineListToRST lst
557+inlineToRST (SmallCaps lst) = writeInlines lst
463558inlineToRST (Quoted SingleQuote lst) = do
464− contents <- inlineListToRST lst
559+ contents <- writeInlines lst
465560 opts <- gets stOptions
466561 if isEnabled Ext_smart opts
467562 then return $ "'" <> contents <> "'"
468563 else return $ "‘" <> contents <> "’"
469564inlineToRST (Quoted DoubleQuote lst) = do
470− contents <- inlineListToRST lst
565+ contents <- writeInlines lst
471566 opts <- gets stOptions
472567 if isEnabled Ext_smart opts
473568 then return $ "\"" <> contents <> "\""
474569 else return $ "“" <> contents <> "”"
475570inlineToRST (Cite _ lst) =
476− inlineListToRST lst
571+ writeInlines lst
477572inlineToRST (Code _ str) = do
478573 opts <- gets stOptions
479574 -- we trim the string because the delimiters must adjoin a
@@ -524,7 +619,7 @@ inlineToRST (Link _ [Image attr alt (imgsrc,imgtit)] (src, _tit)) = do
524619 return $ "|" <> label <> "|"
525620inlineToRST (Link _ txt (src, tit)) = do
526621 useReferenceLinks <- gets $ writerReferenceLinks . stOptions
527− linktext <- inlineListToRST $ B.toList . B.trimInlines . B.fromList $ txt
622+ linktext <- writeInlines $ B.toList . B.trimInlines . B.fromList $ txt
528623 if useReferenceLinks
529624 then do refs <- gets stLinks
530625 case lookup txt refs of
src/Text/Pandoc/Writers/RTF.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE ScopedTypeVariables #-}
23{-
34Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to RTF (rich text format).
3031-}
3132module Text.Pandoc.Writers.RTF ( writeRTF
3233 ) where
34+import Prelude
3335import Control.Monad.Except (catchError, throwError)
3436import Control.Monad
3537import qualified Data.ByteString as B
src/Text/Pandoc/Writers/Shared.hs+33−12
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2013-2018 John MacFarlane <jgm@berkeley.edu>
@@ -41,8 +42,10 @@ module Text.Pandoc.Writers.Shared (
4142 , unsmartify
4243 , gridTable
4344 , metaValueToInlines
45+ , stripLeadingTrailingSpace
4446 )
4547where
48+import Prelude
4649import Control.Monad (zipWithM)
4750import Data.Aeson (FromJSON (..), Result (..), ToJSON (..), Value (Object),
4851 encode, fromJSON)
@@ -240,40 +243,58 @@ gridTable :: Monad m
240243 -> [[[Block]]]
241244 -> m Doc
242245gridTable opts blocksToDoc headless aligns widths headers rows = do
246+ -- the number of columns will be used in case of even widths
243247 let numcols = maximum (length aligns : length widths :
244248 map length (headers:rows))
249+ -- handleGivenWidths wraps the given blocks in order for them to fit
250+ -- in cells with given widths. the returned content can be
251+ -- concatenated with borders and frames
245252 let handleGivenWidths widths' = do
246253 let widthsInChars' = map (
247254 (\x -> if x < 1 then 1 else x) .
248255 (\x -> x - 3) . floor .
249256 (fromIntegral (writerColumns opts) *)
250257 ) widths'
251− rawHeaders' <- zipWithM blocksToDoc
252− (map (\w -> opts{writerColumns =
253− min (w - 2) (writerColumns opts)}) widthsInChars')
254− headers
258+ -- replace page width (in columns) in the options with a
259+ -- given width if smaller (adjusting by two)
260+ useWidth w = opts{writerColumns = min (w - 2) (writerColumns opts)}
261+ -- prepare options to use with header and row cells
262+ columnOptions = map useWidth widthsInChars'
263+ rawHeaders' <- zipWithM blocksToDoc columnOptions headers
255264 rawRows' <- mapM
256− (\cs -> zipWithM blocksToDoc
257− (map (\w -> opts{writerColumns =
258− min (w - 2) (writerColumns opts)}) widthsInChars')
259− cs)
265+ (\cs -> zipWithM blocksToDoc columnOptions cs)
260266 rows
261267 return (widthsInChars', rawHeaders', rawRows')
262− let handleZeroWidths = do
268+ -- handleFullWidths tries to wrap cells to the page width or even
269+ -- more in cases where `--wrap=none`. thus the content here is left
270+ -- as wide as possible
271+ let handleFullWidths = do
263272 rawHeaders' <- mapM (blocksToDoc opts) headers
264273 rawRows' <- mapM (mapM (blocksToDoc opts)) rows
265274 let numChars [] = 0
266275 numChars xs = maximum . map offset $ xs
267276 let widthsInChars' =
268277 map numChars $ transpose (rawHeaders' : rawRows')
278+ return (widthsInChars', rawHeaders', rawRows')
279+ -- handleZeroWidths calls handleFullWidths to check whether a wide
280+ -- table would fit in the page. if the produced table is too wide,
281+ -- it calculates even widths and passes the content to
282+ -- handleGivenWidths
283+ let handleZeroWidths = do
284+ (widthsInChars', rawHeaders', rawRows') <- handleFullWidths
269285 if sum widthsInChars' > writerColumns opts
270286 then -- use even widths
271287 handleGivenWidths
272288 (replicate numcols (1.0 / fromIntegral numcols) :: [Double])
273289 else return (widthsInChars', rawHeaders', rawRows')
274− (widthsInChars, rawHeaders, rawRows) <- if all (== 0) widths
275− then handleZeroWidths
276− else handleGivenWidths widths
290+ -- render the contents of header and row cells differently depending
291+ -- on command line options, widths given in this specific table, and
292+ -- cells' contents
293+ let handleWidths
294+ | writerWrapText opts == WrapNone = handleFullWidths
295+ | all (== 0) widths = handleZeroWidths
296+ | otherwise = handleGivenWidths widths
297+ (widthsInChars, rawHeaders, rawRows) <- handleWidths
277298 let hpipeBlocks blocks = hcat [beg, middle, end]
278299 where h = maximum (1 : map height blocks)
279300 sep' = lblock 3 $ vcat (replicate h (text " | "))
src/Text/Pandoc/Writers/TEI.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE PatternGuards #-}
34{-
@@ -30,6 +31,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3031Conversion of 'Pandoc' documents to Docbook XML.
3132-}
3233module Text.Pandoc.Writers.TEI (writeTEI) where
34+import Prelude
3335import Data.Char (toLower)
3436import Data.List (isPrefixOf, stripPrefix)
3537import Data.Text (Text)
src/Text/Pandoc/Writers/Texinfo.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-
34Copyright (C) 2008-2018 John MacFarlane
@@ -31,6 +32,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
3132Conversion of 'Pandoc' format into Texinfo.
3233-}
3334module Text.Pandoc.Writers.Texinfo ( writeTexinfo ) where
35+import Prelude
3436import Control.Monad.Except (throwError)
3537import Control.Monad.State.Strict
3638import Data.Char (chr, ord)
src/Text/Pandoc/Writers/Textile.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2010-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -30,6 +31,7 @@ Conversion of 'Pandoc' documents to Textile markup.
3031Textile: <http://thresholdstate.com/articles/4312/the-textile-reference-manual>
3132-}
3233module Text.Pandoc.Writers.Textile ( writeTextile ) where
34+import Prelude
3335import Control.Monad.State.Strict
3436import Data.Char (isSpace)
3537import Data.List (intercalate)
src/Text/Pandoc/Writers/ZimWiki.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2008-2018 John MacFarlane <jgm@berkeley.edu>
34 2017-2018 Alex Ivkin
@@ -32,6 +33,7 @@ http://zim-wiki.org/manual/Help/Wiki_Syntax.html
3233-}
3334
3435module Text.Pandoc.Writers.ZimWiki ( writeZimWiki ) where
36+import Prelude
3537import Control.Monad (zipWithM)
3638import Control.Monad.State.Strict (StateT, evalStateT, gets, modify)
3739import Data.Default (Default (..))
src/Text/Pandoc/XML.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-
23Copyright (C) 2006-2018 John MacFarlane <jgm@berkeley.edu>
34
@@ -36,6 +37,7 @@ module Text.Pandoc.XML ( escapeCharForXML,
3637 toEntities,
3738 fromEntities ) where
3839
40+import Prelude
3941import Data.Char (isAscii, isSpace, ord)
4042import Data.Text (Text)
4143import qualified Data.Text as T
stack.lts9.yaml+14−14
@@ -2,7 +2,6 @@ flags:
22 pandoc:
33 trypandoc: false
44 embed_data_files: true
5− old-locale: false
65 network-uri: true
76 pandoc-citeproc:
87 bibutils: true
@@ -13,19 +12,20 @@ flags:
1312packages:
1413- '.'
1514extra-deps:
16−- pandoc-types-1.17.3
17−- hslua-0.9.5
18−- hslua-module-text-0.1.2
19−- skylighting-0.6
20−- ansi-terminal-0.7.1.1
21−- texmath-0.10.1.1
22−- cmark-gfm-0.1.1
23−- QuickCheck-2.10.0.1
15+- hslua-0.9.5.1
16+- hslua-module-text-0.1.2.1
17+- skylighting-0.7.0.2
18+- skylighting-core-0.7.0.2
19+- ansi-terminal-0.8.0.2
20+- cmark-gfm-0.1.3
21+- QuickCheck-2.11.3
22+- tasty-1.0.1.1
2423- tasty-quickcheck-0.9.1
25−- doctemplates-0.2.1
26−- haddock-library-1.4.3
27−- tagsoup-0.14.2
24+- doctemplates-0.2.2.1
2825- hs-bibutils-6.2.0.1
29−- pandoc-citeproc-0.14.1.2
30−- tagsoup-0.14.3
26+- pandoc-citeproc-0.14.3.1
27+- tagsoup-0.14.6
28+- pandoc-types-1.17.4.2
29+- haddock-library-1.5.0.1
30+- texmath-0.10.1.2
3131resolver: lts-9.14
stack.yaml+12−10
@@ -2,7 +2,6 @@ flags:
22 pandoc:
33 trypandoc: false
44 embed_data_files: true
5− old-locale: false
65 network-uri: true
76 pandoc-citeproc:
87 bibutils: true
@@ -13,13 +12,16 @@ flags:
1312packages:
1413- '.'
1514extra-deps:
16−- pandoc-citeproc-0.14.1.2
17−- hslua-0.9.5
18−- skylighting-0.6
19−- ansi-terminal-0.7.1.1
20−- tasty-1.0.0.1
21−- texmath-0.10.1.1
22−- tagsoup-0.14.3
15+- pandoc-citeproc-0.14.3.1
16+- skylighting-0.7.0.2
17+- skylighting-core-0.7.0.2
18+- ansi-terminal-0.8.0.2
19+- tasty-1.0.1.1
20+- test-framework-0.8.2.0
21+- pandoc-types-1.17.4.2
22+- cmark-gfm-0.1.3
23+- hslua-module-text-0.1.2.1
24+- texmath-0.10.1.2
2325ghc-options:
24− "$locals": -fhide-source-paths
25−resolver: lts-10.3
26+ "$locals": -fhide-source-paths -XNoImplicitPrelude
27+resolver: lts-10.10
test/Tests/Command.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Command (findPandoc, runTest, tests)
23where
34
5+import Prelude
46import Data.Algorithm.Diff
57import qualified Data.ByteString as BS
68import Data.List (isSuffixOf)
test/Tests/Command.hs.orignew file+95
@@ -0,0 +1,95 @@
1+module Tests.Command (findPandoc, runTest, tests)
2+where
3+
4+import Data.Algorithm.Diff
5+import qualified Data.ByteString as BS
6+import Data.List (isSuffixOf)
7+import Prelude hiding (readFile)
8+import System.Directory
9+import System.Exit
10+import System.FilePath (joinPath, splitDirectories, takeDirectory, (</>))
11+import System.IO (hPutStr, stderr)
12+import System.IO.Unsafe (unsafePerformIO)
13+import System.Process
14+import Test.Tasty
15+import Test.Tasty.HUnit
16+import Tests.Helpers
17+import Text.Pandoc
18+import qualified Text.Pandoc.UTF8 as UTF8
19+
20+-- | Run a test with normalize function, return True if test passed.
21+runTest :: String -- ^ Title of test
22+ -> FilePath -- ^ Path to pandoc
23+ -> String -- ^ Shell command
24+ -> String -- ^ Input text
25+ -> String -- ^ Expected output
26+ -> TestTree
27+runTest testname pandocpath cmd inp norm = testCase testname $ do
28+ let findDynlibDir [] = Nothing
29+ findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
30+ findDynlibDir (_:xs) = findDynlibDir xs
31+ let mbDynlibDir = findDynlibDir (reverse $ splitDirectories $
32+ takeDirectory $ takeWhile (/=' ') cmd)
33+ let dynlibEnv = case mbDynlibDir of
34+ Nothing -> []
35+ Just d -> [("DYLD_LIBRARY_PATH", d),
36+ ("LD_LIBRARY_PATH", d)]
37+ let env' = dynlibEnv ++ [("PATH",takeDirectory pandocpath),("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),("pandoc_datadir", "..")]
38+ let pr = (shell cmd){ env = Just env' }
39+ (ec, out', err') <- readCreateProcessWithExitCode pr inp
40+ -- filter \r so the tests will work on Windows machines
41+ let out = filter (/= '\r') $ err' ++ out'
42+ result <- if ec == ExitSuccess
43+ then
44+ if out == norm
45+ then return TestPassed
46+ else return
47+ $ TestFailed cmd "expected"
48+ $ getDiff (lines out) (lines norm)
49+ else do
50+ hPutStr stderr err'
51+ return $ TestError ec
52+ assertBool (show result) (result == TestPassed)
53+
54+tests :: TestTree
55+{-# NOINLINE tests #-}
56+tests = unsafePerformIO $ do
57+ pandocpath <- findPandoc
58+ files <- filter (".md" `isSuffixOf`) <$>
59+ getDirectoryContents "command"
60+ let cmds = map (extractCommandTest pandocpath) files
61+ return $ testGroup "Command:" cmds
62+
63+isCodeBlock :: Block -> Bool
64+isCodeBlock (CodeBlock _ _) = True
65+isCodeBlock _ = False
66+
67+extractCode :: Block -> String
68+extractCode (CodeBlock _ code) = code
69+extractCode _ = ""
70+
71+dropPercent :: String -> String
72+dropPercent ('%':xs) = dropWhile (== ' ') xs
73+dropPercent xs = xs
74+
75+runCommandTest :: FilePath -> (Int, String) -> TestTree
76+runCommandTest pandocpath (num, code) =
77+ let codelines = lines code
78+ (continuations, r1) = span ("\\" `isSuffixOf`) codelines
79+ (cmd, r2) = (dropPercent (unwords (map init continuations ++ take 1 r1)),
80+ drop 1 r1)
81+ (inplines, r3) = break (=="^D") r2
82+ normlines = takeWhile (/=".") (drop 1 r3)
83+ input = unlines inplines
84+ norm = unlines normlines
85+ shcmd = cmd -- trimr $ takeDirectory pandocpath </> cmd
86+ in runTest ("#" ++ show num) pandocpath shcmd input norm
87+
88+extractCommandTest :: FilePath -> FilePath -> TestTree
89+extractCommandTest pandocpath fp = unsafePerformIO $ do
90+ contents <- UTF8.toText <$> BS.readFile ("command" </> fp)
91+ Pandoc _ blocks <- runIOorExplode (readMarkdown
92+ def{ readerExtensions = pandocExtensions } contents)
93+ let codeblocks = map extractCode $ filter isCodeBlock blocks
94+ let cases = map (runCommandTest pandocpath) $ zip [1..] codeblocks
95+ return $ testGroup fp cases
test/Tests/Helpers.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE FlexibleInstances #-}
23{-# LANGUAGE TypeSynonymInstances #-}
34-- Utility functions for the test suite.
@@ -13,6 +14,7 @@ module Tests.Helpers ( test
1314 )
1415 where
1516
17+import Prelude
1618import Data.Algorithm.Diff
1719import qualified Data.Map as M
1820import Data.Text (Text, unpack)
test/Tests/Helpers.hs.orignew file+138
@@ -0,0 +1,138 @@
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE TypeSynonymInstances #-}
3+-- Utility functions for the test suite.
4+
5+module Tests.Helpers ( test
6+ , TestResult(..)
7+ , showDiff
8+ , findPandoc
9+ , (=?>)
10+ , purely
11+ , ToString(..)
12+ , ToPandoc(..)
13+ )
14+ where
15+
16+import Data.Algorithm.Diff
17+import qualified Data.Map as M
18+import Data.Text (Text, unpack)
19+import System.Directory
20+import System.Environment.Executable (getExecutablePath)
21+import System.Exit
22+import System.FilePath
23+import Test.Tasty
24+import Test.Tasty.HUnit
25+import Text.Pandoc.Builder (Blocks, Inlines, doc, plain)
26+import Text.Pandoc.Class
27+import Text.Pandoc.Definition
28+import Text.Pandoc.Options
29+import Text.Pandoc.Shared (trimr)
30+import Text.Pandoc.Writers.Native (writeNative)
31+import Text.Printf
32+
33+test :: (ToString a, ToString b, ToString c)
34+ => (a -> b) -- ^ function to test
35+ -> String -- ^ name of test case
36+ -> (a, c) -- ^ (input, expected value)
37+ -> TestTree
38+test fn name (input, expected) =
39+ testCase name' $ assertBool msg (actual' == expected')
40+ where msg = nl ++ dashes "input" ++ nl ++ input' ++ nl ++
41+ dashes "result" ++ nl ++
42+ unlines (map vividize diff) ++
43+ dashes ""
44+ nl = "\n"
45+ name' = if length name > 54
46+ then take 52 name ++ "..." -- avoid wide output
47+ else name
48+ input' = toString input
49+ actual' = lines $ toString $ fn input
50+ expected' = lines $ toString expected
51+ diff = getDiff expected' actual'
52+ dashes "" = replicate 72 '-'
53+ dashes x = replicate (72 - length x - 5) '-' ++ " " ++ x ++ " ---"
54+
55+data TestResult = TestPassed
56+ | TestError ExitCode
57+ | TestFailed String FilePath [Diff String]
58+ deriving (Eq)
59+
60+instance Show TestResult where
61+ show TestPassed = "PASSED"
62+ show (TestError ec) = "ERROR " ++ show ec
63+ show (TestFailed cmd file d) = '\n' : dash ++
64+ "\n--- " ++ file ++
65+ "\n+++ " ++ cmd ++ "\n" ++ showDiff (1,1) d ++
66+ dash
67+ where dash = replicate 72 '-'
68+
69+showDiff :: (Int,Int) -> [Diff String] -> String
70+showDiff _ [] = ""
71+showDiff (l,r) (First ln : ds) =
72+ printf "+%4d " l ++ ln ++ "\n" ++ showDiff (l+1,r) ds
73+showDiff (l,r) (Second ln : ds) =
74+ printf "-%4d " r ++ ln ++ "\n" ++ showDiff (l,r+1) ds
75+showDiff (l,r) (Both _ _ : ds) =
76+ showDiff (l+1,r+1) ds
77+
78+-- | Find pandoc executable relative to test-pandoc
79+-- First, try in same directory (e.g. if both in ~/.cabal/bin)
80+-- Second, try ../pandoc (e.g. if in dist/XXX/build/test-pandoc)
81+findPandoc :: IO FilePath
82+findPandoc = do
83+ testExePath <- getExecutablePath
84+ let testExeDir = takeDirectory testExePath
85+ found <- doesFileExist (testExeDir </> "pandoc")
86+ return $ if found
87+ then testExeDir </> "pandoc"
88+ else case splitDirectories testExeDir of
89+ [] -> error "test-pandoc: empty testExeDir"
90+ xs -> joinPath (init xs) </> "pandoc" </> "pandoc"
91+
92+
93+vividize :: Diff String -> String
94+vividize (Both s _) = " " ++ s
95+vividize (First s) = "- " ++ s
96+vividize (Second s) = "+ " ++ s
97+
98+purely :: (b -> PandocPure a) -> b -> a
99+purely f = either (error . show) id . runPure . f
100+
101+infix 5 =?>
102+(=?>) :: a -> b -> (a,b)
103+x =?> y = (x, y)
104+
105+class ToString a where
106+ toString :: a -> String
107+
108+instance ToString Pandoc where
109+ toString d = unpack $
110+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
111+ where s = case d of
112+ (Pandoc (Meta m) _)
113+ | M.null m -> Nothing
114+ | otherwise -> Just "" -- need this to get meta output
115+
116+instance ToString Blocks where
117+ toString = unpack . purely (writeNative def) . toPandoc
118+
119+instance ToString Inlines where
120+ toString = trimr . unpack . purely (writeNative def) . toPandoc
121+
122+instance ToString String where
123+ toString = id
124+
125+instance ToString Text where
126+ toString = unpack
127+
128+class ToPandoc a where
129+ toPandoc :: a -> Pandoc
130+
131+instance ToPandoc Pandoc where
132+ toPandoc = id
133+
134+instance ToPandoc Blocks where
135+ toPandoc = doc
136+
137+instance ToPandoc Inlines where
138+ toPandoc = doc . plain
test/Tests/Lua.hs+16−1
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Lua ( tests ) where
34
5+import Prelude
46import Control.Monad (when)
57import Data.Version (Version (versionBranch))
68import System.FilePath ((</>))
@@ -10,7 +12,8 @@ import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty)
1012import Text.Pandoc.Arbitrary ()
1113import Text.Pandoc.Builder (bulletList, divWith, doc, doubleQuoted, emph,
1214 header, linebreak, para, plain, rawBlock,
13− singleQuoted, space, str, strong, (<>))
15+ singleQuoted, space, str, strong,
16+ math, displayMath)
1417import Text.Pandoc.Class (runIOorExplode, setUserDataDir)
1518import Text.Pandoc.Definition (Block (BlockQuote, Div, Para), Inline (Emph, Str),
1619 Attr, Meta, Pandoc, pandocTypesVersion)
@@ -46,6 +49,12 @@ tests = map (localOption (QuickCheckTests 20))
4649 (doc $ bulletList [plain (str "alfa"), plain (str "bravo")])
4750 (doc $ bulletList [para (str "alfa"), para (str "bravo")])
4851
52+ , testCase "convert display math to inline math" $
53+ assertFilterConversion "display math becomes inline math"
54+ "math.lua"
55+ (doc $ para (displayMath "5+5"))
56+ (doc $ para (math "5+5"))
57+
4958 , testCase "make hello world document" $
5059 assertFilterConversion "Document contains 'Hello, World!'"
5160 "hello-world-doc.lua"
@@ -111,6 +120,12 @@ tests = map (localOption (QuickCheckTests 20))
111120 , plain (str "to_roman_numeral: OK")
112121 ])
113122
123+ , testCase "Script filename is set" $
124+ assertFilterConversion "unexpected script name"
125+ "script-name.lua"
126+ (doc $ para "ignored")
127+ (doc $ para (str $ "lua" </> "script-name.lua"))
128+
114129 , testCase "Pandoc version is set" . runPandocLua' $ do
115130 Lua.getglobal' "table.concat"
116131 Lua.getglobal "PANDOC_VERSION"
test/Tests/Lua.hs.orignew file+196
@@ -0,0 +1,196 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Lua ( tests ) where
3+
4+import Control.Monad (when)
5+import Data.Version (Version (versionBranch))
6+import System.FilePath ((</>))
7+import Test.Tasty (TestTree, localOption)
8+import Test.Tasty.HUnit (Assertion, assertEqual, testCase)
9+import Test.Tasty.QuickCheck (QuickCheckTests (..), ioProperty, testProperty)
10+import Text.Pandoc.Arbitrary ()
11+import Text.Pandoc.Builder (bulletList, divWith, doc, doubleQuoted, emph,
12+ header, linebreak, para, plain, rawBlock,
13+ singleQuoted, space, str, strong)
14+import Text.Pandoc.Class (runIOorExplode, setUserDataDir)
15+import Text.Pandoc.Definition (Block (BlockQuote, Div, Para), Inline (Emph, Str),
16+ Attr, Meta, Pandoc, pandocTypesVersion)
17+import Text.Pandoc.Lua (runLuaFilter, runPandocLua)
18+import Text.Pandoc.Options (def)
19+import Text.Pandoc.Shared (pandocVersion)
20+
21+import qualified Foreign.Lua as Lua
22+
23+tests :: [TestTree]
24+tests = map (localOption (QuickCheckTests 20))
25+ [ testProperty "inline elements can be round-tripped through the lua stack" $
26+ \x -> ioProperty (roundtripEqual (x::Inline))
27+
28+ , testProperty "block elements can be round-tripped through the lua stack" $
29+ \x -> ioProperty (roundtripEqual (x::Block))
30+
31+ , testProperty "meta blocks can be round-tripped through the lua stack" $
32+ \x -> ioProperty (roundtripEqual (x::Meta))
33+
34+ , testProperty "documents can be round-tripped through the lua stack" $
35+ \x -> ioProperty (roundtripEqual (x::Pandoc))
36+
37+ , testCase "macro expansion via filter" $
38+ assertFilterConversion "a '{{helloworld}}' string is expanded"
39+ "strmacro.lua"
40+ (doc . para $ str "{{helloworld}}")
41+ (doc . para . emph $ str "Hello, World")
42+
43+ , testCase "convert all plains to paras" $
44+ assertFilterConversion "plains become para"
45+ "plain-to-para.lua"
46+ (doc $ bulletList [plain (str "alfa"), plain (str "bravo")])
47+ (doc $ bulletList [para (str "alfa"), para (str "bravo")])
48+
49+ , testCase "make hello world document" $
50+ assertFilterConversion "Document contains 'Hello, World!'"
51+ "hello-world-doc.lua"
52+ (doc . para $ str "Hey!" <> linebreak <> str "What's up?")
53+ (doc . para $ str "Hello," <> space <> str "World!")
54+
55+ , testCase "implicit doc filter" $
56+ assertFilterConversion "Document contains 'Hello, World!'"
57+ "implicit-doc-filter.lua"
58+ (doc . plain $ linebreak)
59+ (doc . para $ str "Hello," <> space <> str "World!")
60+
61+ , testCase "parse raw markdown blocks" $
62+ assertFilterConversion "raw markdown block is converted"
63+ "markdown-reader.lua"
64+ (doc $ rawBlock "markdown" "*charly* **delta**")
65+ (doc . para $ emph "charly" <> space <> strong "delta")
66+
67+ , testCase "allow shorthand functions for quote types" $
68+ assertFilterConversion "single quoted becomes double quoted string"
69+ "single-to-double-quoted.lua"
70+ (doc . para . singleQuoted $ str "simple")
71+ (doc . para . doubleQuoted $ str "simple")
72+
73+ , testCase "Count inlines via metatable catch-all" $
74+ assertFilterConversion "filtering with metatable catch-all failed"
75+ "metatable-catch-all.lua"
76+ (doc . para $ "four words, three spaces")
77+ (doc . para $ str "7")
78+
79+ , testCase "Count blocks via Block-specific catch-all" $
80+ assertFilterConversion "filtering with Block catch-all failed"
81+ "block-count.lua"
82+ (doc $ para "one" <> para "two")
83+ (doc $ para "2")
84+
85+ , testCase "Convert header upper case" $
86+ assertFilterConversion "converting header to upper case failed"
87+ "uppercase-header.lua"
88+ (doc $ header 1 "les états-unis" <> para "text")
89+ (doc $ header 1 "LES ÉTATS-UNIS" <> para "text")
90+
91+ , testCase "Attribute lists are convenient to use" $
92+ let kv_before = [("one", "1"), ("two", "2"), ("three", "3")]
93+ kv_after = [("one", "eins"), ("three", "3"), ("five", "5")]
94+ in assertFilterConversion "Attr doesn't behave as expected"
95+ "attr-test.lua"
96+ (doc $ divWith ("", [], kv_before) (para "nil"))
97+ (doc $ divWith ("", [], kv_after) (para "nil"))
98+
99+ , testCase "Test module pandoc.utils" $
100+ assertFilterConversion "pandoc.utils doesn't work as expected."
101+ "test-pandoc-utils.lua"
102+ (doc $ para "doesn't matter")
103+ (doc $ mconcat [ plain (str "hierarchicalize: OK")
104+ , plain (str "normalize_date: OK")
105+ , plain (str "pipe: OK")
106+ , plain (str "failing pipe: OK")
107+ , plain (str "read: OK")
108+ , plain (str "failing read: OK")
109+ , plain (str "sha1: OK")
110+ , plain (str "stringify: OK")
111+ , plain (str "to_roman_numeral: OK")
112+ ])
113+
114+ , testCase "Script filename is set" $
115+ assertFilterConversion "unexpected script name"
116+ "script-name.lua"
117+ (doc $ para "ignored")
118+ (doc $ para (str $ "lua" </> "script-name.lua"))
119+
120+ , testCase "Pandoc version is set" . runPandocLua' $ do
121+ Lua.getglobal' "table.concat"
122+ Lua.getglobal "PANDOC_VERSION"
123+ Lua.push ("." :: String) -- seperator
124+ Lua.call 2 1
125+ Lua.liftIO . assertEqual "pandoc version is wrong" pandocVersion
126+ =<< Lua.peek Lua.stackTop
127+
128+ , testCase "Pandoc types version is set" . runPandocLua' $ do
129+ let versionNums = versionBranch pandocTypesVersion
130+ Lua.getglobal "PANDOC_API_VERSION"
131+ Lua.liftIO . assertEqual "pandoc-types version is wrong" versionNums
132+ =<< Lua.peek Lua.stackTop
133+
134+ , testCase "Allow singleton inline in constructors" . runPandocLua' $ do
135+ Lua.liftIO . assertEqual "Not the exptected Emph" (Emph [Str "test"])
136+ =<< Lua.callFunc "pandoc.Emph" (Str "test")
137+ Lua.liftIO . assertEqual "Unexpected element" (Para [Str "test"])
138+ =<< Lua.callFunc "pandoc.Para" ("test" :: String)
139+ Lua.liftIO . assertEqual "Unexptected element"
140+ (BlockQuote [Para [Str "foo"]]) =<< (
141+ do
142+ Lua.getglobal' "pandoc.BlockQuote"
143+ Lua.push (Para [Str "foo"])
144+ _ <- Lua.call 1 1
145+ Lua.peek Lua.stackTop
146+ )
147+
148+ , testCase "Elements with Attr have `attr` accessor" . runPandocLua' $ do
149+ Lua.push (Div ("hi", ["moin"], [])
150+ [Para [Str "ignored"]])
151+ Lua.getfield Lua.stackTop "attr"
152+ Lua.liftIO . assertEqual "no accessor" (("hi", ["moin"], []) :: Attr)
153+ =<< Lua.peek Lua.stackTop
154+
155+ , testCase "informative error messages" . runPandocLua' $ do
156+ Lua.pushboolean True
157+ err <- Lua.peekEither Lua.stackTop :: Lua.Lua (Either String Pandoc)
158+ case err of
159+ Left msg -> do
160+ let expectedMsg = "Could not get Pandoc value: "
161+ ++ "expected table but got boolean."
162+ Lua.liftIO $ assertEqual "unexpected error message" expectedMsg msg
163+ Right _ -> error "Getting a Pandoc element from a bool should fail."
164+ ]
165+
166+assertFilterConversion :: String -> FilePath -> Pandoc -> Pandoc -> Assertion
167+assertFilterConversion msg filterPath docIn docExpected = do
168+ docEither <- runIOorExplode $ do
169+ setUserDataDir (Just "../data")
170+ runLuaFilter def ("lua" </> filterPath) [] docIn
171+ case docEither of
172+ Left _ -> fail "lua filter failed"
173+ Right docRes -> assertEqual msg docExpected docRes
174+
175+roundtripEqual :: (Eq a, Lua.FromLuaStack a, Lua.ToLuaStack a) => a -> IO Bool
176+roundtripEqual x = (x ==) <$> roundtripped
177+ where
178+ roundtripped :: (Lua.FromLuaStack a, Lua.ToLuaStack a) => IO a
179+ roundtripped = runPandocLua' $ do
180+ oldSize <- Lua.gettop
181+ Lua.push x
182+ size <- Lua.gettop
183+ when (size - oldSize /= 1) $
184+ error ("not exactly one additional element on the stack: " ++ show size)
185+ res <- Lua.peekEither (-1)
186+ case res of
187+ Left e -> error (show e)
188+ Right y -> return y
189+
190+runPandocLua' :: Lua.Lua a -> IO a
191+runPandocLua' op = runIOorExplode $ do
192+ setUserDataDir (Just "../data")
193+ res <- runPandocLua op
194+ case res of
195+ Left e -> error (show e)
196+ Right x -> return x
test/Tests/Old.hs+4−2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Old (tests) where
23
4+import Prelude
35import Data.Algorithm.Diff
46import Prelude hiding (readFile)
57import System.Exit
@@ -57,7 +59,7 @@ tests = [ testGroup "markdown"
5759 ]
5860 , testGroup "s5"
5961 [ s5WriterTest "basic" ["-s"] "s5"
60− , s5WriterTest "fancy" ["-s","-m","-i"] "s5"
62+ , s5WriterTest "fancy" ["-s","--mathjax","-i"] "s5"
6163 , s5WriterTest "fragment" [] "html4"
6264 , s5WriterTest "inserts" ["-s", "-H", "insert",
6365 "-B", "insert", "-A", "insert", "-c", "main.css"] "html4"
@@ -93,6 +95,7 @@ tests = [ testGroup "markdown"
9395 , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2"
9496 , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2"
9597 , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2"
98+ , fb2WriterTest "meta" [] "fb2/meta.markdown" "fb2/meta.fb2"
9699 , fb2WriterTest "tables" [] "tables.native" "tables.fb2"
97100 , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2"
98101 ]
@@ -286,4 +289,3 @@ findDynlibDir :: [FilePath] -> Maybe FilePath
286289findDynlibDir [] = Nothing
287290findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
288291findDynlibDir (_:xs) = findDynlibDir xs
289−
test/Tests/Old.hs.orignew file+288
@@ -0,0 +1,288 @@
1+module Tests.Old (tests) where
2+
3+import Data.Algorithm.Diff
4+import Prelude hiding (readFile)
5+import System.Exit
6+import System.FilePath (joinPath, splitDirectories, (<.>), (</>))
7+import System.IO.Temp (withTempFile)
8+import System.Process (runProcess, waitForProcess)
9+import Test.Tasty (TestTree, testGroup)
10+import Test.Tasty.Golden.Advanced (goldenTest)
11+import Tests.Helpers hiding (test)
12+import qualified Text.Pandoc.UTF8 as UTF8
13+
14+tests :: [TestTree]
15+tests = [ testGroup "markdown"
16+ [ testGroup "writer"
17+ $ writerTests "markdown" ++ lhsWriterTests "markdown"
18+ , testGroup "reader"
19+ [ test "basic" ["-r", "markdown", "-w", "native", "-s"]
20+ "testsuite.txt" "testsuite.native"
21+ , test "tables" ["-r", "markdown", "-w", "native", "--columns=80"]
22+ "tables.txt" "tables.native"
23+ , test "pipe tables" ["-r", "markdown", "-w", "native", "--columns=80"]
24+ "pipe-tables.txt" "pipe-tables.native"
25+ , test "more" ["-r", "markdown", "-w", "native", "-s"]
26+ "markdown-reader-more.txt" "markdown-reader-more.native"
27+ , lhsReaderTest "markdown+lhs"
28+ ]
29+ , testGroup "citations"
30+ [ test "citations" ["-r", "markdown", "-w", "native"]
31+ "markdown-citations.txt" "markdown-citations.native"
32+ ]
33+ ]
34+ , testGroup "rst"
35+ [ testGroup "writer" (writerTests "rst" ++ lhsWriterTests "rst")
36+ , testGroup "reader"
37+ [ test "basic" ["-r", "rst+smart", "-w", "native",
38+ "-s", "--columns=80"] "rst-reader.rst" "rst-reader.native"
39+ , test "tables" ["-r", "rst", "-w", "native", "--columns=80"]
40+ "tables.rst" "tables-rstsubset.native"
41+ , lhsReaderTest "rst+lhs"
42+ ]
43+ ]
44+ , testGroup "latex"
45+ [ testGroup "writer" (writerTests "latex" ++ lhsWriterTests "latex")
46+ , testGroup "reader"
47+ [ test "basic" ["-r", "latex+raw_tex", "-w", "native", "-s"]
48+ "latex-reader.latex" "latex-reader.native"
49+ , lhsReaderTest "latex+lhs"
50+ ]
51+ ]
52+ , testGroup "html"
53+ [ testGroup "writer" (writerTests "html4" ++ writerTests "html5" ++
54+ lhsWriterTests "html")
55+ , test "reader" ["-r", "html", "-w", "native", "-s"]
56+ "html-reader.html" "html-reader.native"
57+ ]
58+ , testGroup "s5"
59+ [ s5WriterTest "basic" ["-s"] "s5"
60+ , s5WriterTest "fancy" ["-s","-m","-i"] "s5"
61+ , s5WriterTest "fragment" [] "html4"
62+ , s5WriterTest "inserts" ["-s", "-H", "insert",
63+ "-B", "insert", "-A", "insert", "-c", "main.css"] "html4"
64+ ]
65+ , testGroup "textile"
66+ [ testGroup "writer" $ writerTests "textile"
67+ , test "reader" ["-r", "textile", "-w", "native", "-s"]
68+ "textile-reader.textile" "textile-reader.native"
69+ ]
70+ , testGroup "docbook"
71+ [ testGroup "writer" $ writerTests "docbook4"
72+ , test "reader" ["-r", "docbook", "-w", "native", "-s"]
73+ "docbook-reader.docbook" "docbook-reader.native"
74+ , test "reader" ["-r", "docbook", "-w", "native", "-s"]
75+ "docbook-xref.docbook" "docbook-xref.native"
76+ ]
77+ , testGroup "docbook5"
78+ [ testGroup "writer" $ writerTests "docbook5"
79+ ]
80+ , testGroup "jats"
81+ [ testGroup "writer" $ writerTests "jats"
82+ , test "reader" ["-r", "jats", "-w", "native", "-s"]
83+ "jats-reader.xml" "jats-reader.native"
84+ ]
85+ , testGroup "native"
86+ [ testGroup "writer" $ writerTests "native"
87+ , test "reader" ["-r", "native", "-w", "native", "-s"]
88+ "testsuite.native" "testsuite.native"
89+ ]
90+ , testGroup "fb2"
91+ [ fb2WriterTest "basic" [] "fb2/basic.markdown" "fb2/basic.fb2"
92+ , fb2WriterTest "titles" [] "fb2/titles.markdown" "fb2/titles.fb2"
93+ , fb2WriterTest "images" [] "fb2/images.markdown" "fb2/images.fb2"
94+ , fb2WriterTest "images-embedded" [] "fb2/images-embedded.html" "fb2/images-embedded.fb2"
95+ , fb2WriterTest "math" [] "fb2/math.markdown" "fb2/math.fb2"
96+ , fb2WriterTest "tables" [] "tables.native" "tables.fb2"
97+ , fb2WriterTest "testsuite" [] "testsuite.native" "writer.fb2"
98+ ]
99+ , testGroup "mediawiki"
100+ [ testGroup "writer" $ writerTests "mediawiki"
101+ , test "reader" ["-r", "mediawiki", "-w", "native", "-s"]
102+ "mediawiki-reader.wiki" "mediawiki-reader.native"
103+ ]
104+ , testGroup "vimwiki"
105+ [ test "reader" ["-r", "vimwiki", "-w", "native", "-s"]
106+ "vimwiki-reader.wiki" "vimwiki-reader.native"
107+ ]
108+ , testGroup "dokuwiki"
109+ [ testGroup "writer" $ writerTests "dokuwiki"
110+ , test "inline_formatting" ["-r", "native", "-w", "dokuwiki", "-s"]
111+ "dokuwiki_inline_formatting.native" "dokuwiki_inline_formatting.dokuwiki"
112+ , test "multiblock table" ["-r", "native", "-w", "dokuwiki", "-s"]
113+ "dokuwiki_multiblock_table.native" "dokuwiki_multiblock_table.dokuwiki"
114+ , test "external images" ["-r", "native", "-w", "dokuwiki", "-s"]
115+ "dokuwiki_external_images.native" "dokuwiki_external_images.dokuwiki"
116+ ]
117+ , testGroup "opml"
118+ [ test "basic" ["-r", "native", "-w", "opml", "--columns=78", "-s"]
119+ "testsuite.native" "writer.opml"
120+ , test "reader" ["-r", "opml", "-w", "native", "-s"]
121+ "opml-reader.opml" "opml-reader.native"
122+ ]
123+ , testGroup "haddock"
124+ [ testGroup "writer" $ writerTests "haddock"
125+ , test "reader" ["-r", "haddock", "-w", "native", "-s"]
126+ "haddock-reader.haddock" "haddock-reader.native"
127+ ]
128+ , testGroup "txt2tags"
129+ [ test "reader" ["-r", "t2t", "-w", "native", "-s"]
130+ "txt2tags.t2t" "txt2tags.native" ]
131+ , testGroup "epub" [
132+ test "features" ["-r", "epub", "-w", "native"]
133+ "epub/features.epub" "epub/features.native"
134+ , test "wasteland" ["-r", "epub", "-w", "native"]
135+ "epub/wasteland.epub" "epub/wasteland.native"
136+ , test "formatting" ["-r", "epub", "-w", "native"]
137+ "epub/formatting.epub" "epub/formatting.native"
138+ ]
139+ , testGroup "twiki"
140+ [ test "reader" ["-r", "twiki", "-w", "native", "-s"]
141+ "twiki-reader.twiki" "twiki-reader.native" ]
142+ , testGroup "tikiwiki"
143+ [ test "reader" ["-r", "tikiwiki", "-w", "native", "-s"]
144+ "tikiwiki-reader.tikiwiki" "tikiwiki-reader.native" ]
145+ , testGroup "other writers" $ map (\f -> testGroup f $ writerTests f)
146+ [ "opendocument" , "context" , "texinfo", "icml", "tei"
147+ , "man" , "plain" , "rtf", "org", "asciidoc", "zimwiki"
148+ ]
149+ , testGroup "writers-lang-and-dir"
150+ [ test "latex" ["-f", "native", "-t", "latex", "-s"]
151+ "writers-lang-and-dir.native" "writers-lang-and-dir.latex"
152+ , test "context" ["-f", "native", "-t", "context", "-s"]
153+ "writers-lang-and-dir.native" "writers-lang-and-dir.context"
154+ ]
155+ , testGroup "muse"
156+ [ testGroup "writer" $ writerTests "muse"
157+ ]
158+ , testGroup "ms"
159+ [ testGroup "writer" $ writerTests "ms"
160+ ]
161+ , testGroup "creole"
162+ [ test "reader" ["-r", "creole", "-w", "native", "-s"]
163+ "creole-reader.txt" "creole-reader.native"
164+ ]
165+ , testGroup "custom writer"
166+ [ test "basic" ["-f", "native", "-t", "../data/sample.lua"]
167+ "testsuite.native" "writer.custom"
168+ , test "tables" ["-f", "native", "-t", "../data/sample.lua"]
169+ "tables.native" "tables.custom"
170+ ]
171+ ]
172+
173+-- makes sure file is fully closed after reading
174+readFile' :: FilePath -> IO String
175+readFile' f = do s <- UTF8.readFile f
176+ return $! (length s `seq` s)
177+
178+lhsWriterTests :: String -> [TestTree]
179+lhsWriterTests format
180+ = [ t "lhs to normal" format
181+ , t "lhs to lhs" (format ++ "+lhs")
182+ ]
183+ where
184+ t n f = test n ["--wrap=preserve", "-r", "native", "-s", "-w", f]
185+ "lhs-test.native" ("lhs-test" <.> f)
186+
187+lhsReaderTest :: String -> TestTree
188+lhsReaderTest format =
189+ test "lhs" ["-r", format, "-w", "native"]
190+ ("lhs-test" <.> format) norm
191+ where norm = if format == "markdown+lhs"
192+ then "lhs-test-markdown.native"
193+ else "lhs-test.native"
194+
195+writerTests :: String -> [TestTree]
196+writerTests format
197+ = [ test "basic" (opts ++ ["-s"]) "testsuite.native" ("writer" <.> format)
198+ , test "tables" opts "tables.native" ("tables" <.> format)
199+ ]
200+ where
201+ opts = ["-r", "native", "-w", format, "--columns=78",
202+ "--variable", "pandoc-version="]
203+
204+s5WriterTest :: String -> [String] -> String -> TestTree
205+s5WriterTest modifier opts format
206+ = test (format ++ " writer (" ++ modifier ++ ")")
207+ (["-r", "native", "-w", format] ++ opts)
208+ "s5.native" ("s5-" ++ modifier <.> "html")
209+
210+fb2WriterTest :: String -> [String] -> String -> String -> TestTree
211+fb2WriterTest title opts inputfile normfile =
212+ testWithNormalize (ignoreBinary . formatXML)
213+ title (["-t", "fb2"]++opts) inputfile normfile
214+ where
215+ formatXML xml = splitTags $ zip xml (drop 1 xml)
216+ splitTags [] = []
217+ splitTags [end] = fst end : snd end : []
218+ splitTags (('>','<'):rest) = ">\n" ++ splitTags rest
219+ splitTags ((c,_):rest) = c : splitTags rest
220+ ignoreBinary = unlines . filter (not . startsWith "<binary ") . lines
221+ startsWith tag str = all (uncurry (==)) $ zip tag str
222+
223+-- | Run a test without normalize function, return True if test passed.
224+test :: String -- ^ Title of test
225+ -> [String] -- ^ Options to pass to pandoc
226+ -> String -- ^ Input filepath
227+ -> FilePath -- ^ Norm (for test results) filepath
228+ -> TestTree
229+test = testWithNormalize id
230+
231+-- | Run a test with normalize function, return True if test passed.
232+testWithNormalize :: (String -> String) -- ^ Normalize function for output
233+ -> String -- ^ Title of test
234+ -> [String] -- ^ Options to pass to pandoc
235+ -> String -- ^ Input filepath
236+ -> FilePath -- ^ Norm (for test results) filepath
237+ -> TestTree
238+testWithNormalize normalizer testname opts inp norm =
239+ goldenTest testname getExpected getActual
240+ (compareValues norm options) updateGolden
241+ where getExpected = normalizer <$> readFile' norm
242+ getActual =
243+ withTempFile "." "pandoc-test" $ \outputPath hOut -> do
244+ withTempFile "." "pandoc-test" $ \errorPath hErr -> do
245+ pandocPath <- findPandoc
246+ let mbDynlibDir = findDynlibDir (reverse $
247+ splitDirectories pandocPath)
248+ let dynlibEnv = case mbDynlibDir of
249+ Nothing -> []
250+ Just d -> [("DYLD_LIBRARY_PATH", d),
251+ ("LD_LIBRARY_PATH", d)]
252+ let env = dynlibEnv ++
253+ [("TMP","."),("LANG","en_US.UTF-8"),("HOME", "./"),
254+ ("pandoc_datadir","..")]
255+ ph <- runProcess pandocPath options Nothing
256+ (Just env) Nothing (Just hOut) (Just hErr)
257+ ec <- waitForProcess ph
258+ if ec == ExitSuccess
259+ then
260+ -- filter \r so the tests will work on Windows machines
261+ (filter (/='\r') . normalizer) <$> readFile' outputPath
262+ else do
263+ errcontents <- UTF8.readFile errorPath
264+ fail $ "Pandoc failed with " ++ show ec ++
265+ if null errcontents
266+ then ""
267+ else '\n':errcontents
268+ updateGolden = UTF8.writeFile norm
269+ options = ["--quiet"] ++ [inp] ++ opts
270+
271+compareValues :: FilePath -> [String] -> String -> String -> IO (Maybe String)
272+compareValues norm options expected actual = do
273+ pandocPath <- findPandoc
274+ let cmd = pandocPath ++ " " ++ unwords options
275+ let dash = replicate 72 '-'
276+ let diff = getDiff (lines actual) (lines expected)
277+ if expected == actual
278+ then return Nothing
279+ else return $ Just $
280+ '\n' : dash ++
281+ "\n--- " ++ norm ++
282+ "\n+++ " ++ cmd ++ "\n" ++
283+ showDiff (1,1) diff ++ dash
284+
285+findDynlibDir :: [FilePath] -> Maybe FilePath
286+findDynlibDir [] = Nothing
287+findDynlibDir ("build":xs) = Just $ joinPath (reverse xs) </> "build"
288+findDynlibDir (_:xs) = findDynlibDir xs
test/Tests/Readers/Creole.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Creole (tests) where
34
5+import Prelude
46import Data.Text (Text)
57import qualified Data.Text as T
68import Test.Tasty
test/Tests/Readers/Creole.hs.orignew file+286
@@ -0,0 +1,286 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Creole (tests) where
3+
4+import Data.Text (Text)
5+import qualified Data.Text as T
6+import Test.Tasty
7+import Tests.Helpers
8+import Text.Pandoc
9+import Text.Pandoc.Arbitrary ()
10+import Text.Pandoc.Builder
11+
12+creole :: Text -> Pandoc
13+creole = purely $ readCreole def{ readerStandalone = True }
14+
15+infix 4 =:
16+(=:) :: ToString c
17+ => String -> (Text, c) -> TestTree
18+(=:) = test creole
19+
20+tests :: [TestTree]
21+tests = [
22+ testGroup "Basic Text Formatting" [
23+ "bold, single line, fully delimited" =:
24+ "only **bold** is bold"
25+ =?> para ("only " <> strong "bold" <> " is bold")
26+ , "italics, single line, fully delimited" =:
27+ "only //this// is in italics"
28+ =?> para ("only " <> emph "this" <> " is in italics")
29+ , "bold in italics, fully delimited" =:
30+ "//**this**// is in bold italics"
31+ =?> para (emph (strong "this") <> " is in bold italics")
32+ , "italics in bold, fully delimited" =:
33+ "**//this//** is in bold italics"
34+ =?> para (strong (emph "this") <> " is in bold italics")
35+
36+ , "escape bold marker" =:
37+ "~**not bold" =?> para "**not bold"
38+ , "escape italics marker" =:
39+ "~//not in italics" =?> para "//not in italics"
40+
41+ , "inline nowiki, simple" =:
42+ "this is {{{**not** ~interpreted}}} at all"
43+ =?> para ("this is " <> code "**not** ~interpreted" <> " at all")
44+ , "inline nowiki, curly braces inside" =:
45+ "this is {{{{{{//including// some `}' chars}}}}}}"
46+ =?> para ("this is " <> code "{{{//including// some `}' chars}}}")
47+
48+ , "placeholder" =:
49+ "foo <<<place holder>>> bar"
50+ =?> para "foo bar"
51+ , "placeholder escaped" =:
52+ "foo ~<<<no place holder>>> bar"
53+ =?> para "foo <<<no place holder>>> bar"
54+ ]
55+ , testGroup "Headers" [
56+ "header level 1, no space, no trailing =" =:
57+ "= Top-Level Header"
58+ =?> header 1 (str "Top-Level Header")
59+ , "header level 1, leading space, trailing =" =:
60+ " = Top-Level Header = "
61+ =?> header 1 (str "Top-Level Header")
62+ , "header level 2, no space, no trailing =" =:
63+ "== Second Level"
64+ =?> header 2 (str "Second Level")
65+ , "header level 2, leading space, no trailing =" =:
66+ " == Second Level"
67+ =?> header 2 (str "Second Level")
68+ , "header level 3, no space, no trailing =" =:
69+ "=== Third"
70+ =?> header 3 (str "Third")
71+ , "header level 3, no space, > 3 trailing =" =:
72+ "=== Third ======="
73+ =?> header 3 (str "Third")
74+ , "header level 4, no space, no trailing =" =:
75+ "==== Fourth Level Heading"
76+ =?> header 4 (str "Fourth Level Heading")
77+ , "header level 4, no space, < 4 trailing =" =:
78+ "==== Fourth Level Heading =="
79+ =?> header 4 (str "Fourth Level Heading")
80+ , "header level 5, no space, no trailing =" =:
81+ "===== Fifth"
82+ =?> header 5 (str "Fifth")
83+ , "header level 6, no space, no trailing =" =:
84+ "====== Sixth"
85+ =?> header 6 (str "Sixth")
86+ ]
87+ , testGroup "Paragraphs" [
88+ "paragraphs: multiple, one line" =:
89+ "first line\n\nanother line\n"
90+ =?> para "first line" <> para "another line"
91+ ]
92+ , testGroup "Lists" [
93+ "unordered list, two entries, one separating space" =:
94+ "* foo\n* bar"
95+ =?> bulletList [ plain "foo", plain "bar" ]
96+ , "unordered list, three entries, one separating space" =:
97+ "* foo\n* bar\n* baz"
98+ =?> bulletList [ plain "foo", plain "bar", plain "baz" ]
99+ , "para followed by, unordered list, two entries, one separating space" =:
100+ "blubber\n* foo\n* bar"
101+ =?> para "blubber" <> bulletList [ plain "foo", plain "bar" ]
102+ , "nested unordered list, one separating space" =:
103+ "* foo\n** bar\n** baz\n* blubb"
104+ =?> bulletList [ plain "foo"
105+ <> bulletList [ plain "bar", plain "baz" ]
106+ , plain "blubb" ]
107+ , "nested many unordered lists, one separating space" =:
108+ ("* foo\n** bar\n*** third\n*** third two\n** baz\n*** third again\n"
109+ <> "**** fourth\n***** fith\n* blubb")
110+ =?> bulletList [ plain "foo"
111+ <> bulletList [ plain "bar"
112+ <> bulletList [ plain "third"
113+ , plain "third two"]
114+ , plain "baz"
115+ <> bulletList [ plain "third again"
116+ <> bulletList [
117+ plain "fourth"
118+ <> bulletList [
119+ plain "fith"
120+ ]
121+ ]
122+ ]
123+ ]
124+ , plain "blubb" ]
125+ , "nested unordered list, mixed separating space" =:
126+ "*foo\n ** bar\n **baz\n * blubb"
127+ =?> bulletList [ plain "foo"
128+ <> bulletList [ plain "bar", plain "baz" ]
129+ , plain "blubb" ]
130+ , "nested unordered list, one separating space, trailing space" =:
131+ "* foo \n** bar \n** baz \n* blubb "
132+ =?> bulletList [ plain "foo"
133+ <> bulletList [ plain "bar", plain "baz" ]
134+ , plain "blubb" ]
135+ , "ordered list, two entries, one separating space" =:
136+ "# foo\n# bar"
137+ =?> orderedList [ plain "foo", plain "bar" ]
138+ , "ordered list, three entries, one separating space" =:
139+ "# foo\n# bar\n# baz"
140+ =?> orderedList [ plain "foo", plain "bar", plain "baz" ]
141+ , "para followed by, ordered list, two entries, one separating space" =:
142+ "blubber\n# foo\n# bar"
143+ =?> para "blubber" <> orderedList [ plain "foo", plain "bar" ]
144+ , "nested ordered list, one separating space" =:
145+ "# foo\n## bar\n## baz\n# blubb"
146+ =?> orderedList [ plain "foo"
147+ <> orderedList [ plain "bar", plain "baz" ]
148+ , plain "blubb" ]
149+ , "nested ordered list, one separating space, trailing space" =:
150+ "# foo \n## bar \n## baz \n# blubb "
151+ =?> orderedList [ plain "foo"
152+ <> orderedList [ plain "bar", plain "baz" ]
153+ , plain "blubb" ]
154+ , "nested many ordered lists, one separating space" =:
155+ ("# foo\n## bar\n### third\n### third two\n## baz\n### third again\n"
156+ <> "#### fourth\n##### fith\n# blubb")
157+ =?> orderedList [ plain "foo"
158+ <> orderedList [ plain "bar"
159+ <> orderedList [ plain "third"
160+ , plain "third two"]
161+ , plain "baz"
162+ <> orderedList [ plain "third again"
163+ <> orderedList [
164+ plain "fourth"
165+ <> orderedList [
166+ plain "fith"
167+ ]
168+ ]
169+ ]
170+ ]
171+ , plain "blubb" ]
172+ , "nested ordered list, mixed separating space" =:
173+ "#foo\n ## bar\n ##baz\n # blubb"
174+ =?> orderedList [ plain "foo"
175+ <> orderedList [ plain "bar", plain "baz" ]
176+ , plain "blubb" ]
177+ , "mixed nested ordered and unordered lists, one separating space" =:
178+ ("# foo\n** bar\n### third\n### third two\n** baz\n### third again\n"
179+ <> "#### fourth\n***** fith\n# blubb")
180+ =?> orderedList [ plain "foo"
181+ <> bulletList [ plain "bar"
182+ <> orderedList [ plain "third"
183+ , plain "third two"]
184+ , plain "baz"
185+ <> orderedList [ plain "third again"
186+ <> orderedList [
187+ plain "fourth"
188+ <> bulletList [
189+ plain "fith"
190+ ]
191+ ]
192+ ]
193+ ]
194+ , plain "blubb" ]
195+ ]
196+ , testGroup "NoWiki" [
197+ "quoted block, simple" =:
198+ "{{{\nfoo bar\n //baz//\n}}}"
199+ =?> codeBlock "foo bar\n //baz//"
200+ , "quoted block, curly bracket exception" =:
201+ "{{{\nfoo bar\n }}}\nbaz\n }}}\n}}}"
202+ =?> codeBlock "foo bar\n }}}\nbaz\n}}}"
203+ , "forced line breaks" =:
204+ "{{{no break!\\\\here}}} but a break\\\\here!"
205+ =?> para (code "no break!\\\\here" <> " but a break"
206+ <> linebreak <> "here!"),
207+ "quoted block, after trailing white space" =:
208+ "this is a paragraph \n{{{\nfoo bar\n //baz//\n}}}"
209+ =?> para "this is a paragraph" <> codeBlock "foo bar\n //baz//"
210+ ]
211+ , testGroup "Images and Links" [
212+ "image simple" =:
213+ "{{foo.png}}" =?> para (image "foo.png" "" (str ""))
214+ , "image with alt text" =:
215+ "Image of a bar: {{/path/to/bar.png|A Bar}} look at it!"
216+ =?> para ("Image of a bar: "
217+ <> image "/path/to/bar.png" "" (str "A Bar") <> " look at it!")
218+
219+ , "auto link" =:
220+ "foo http://foo.example.com/bar/baz.html bar"
221+ =?> para ("foo "
222+ <> link "http://foo.example.com/bar/baz.html" ""
223+ (str "http://foo.example.com/bar/baz.html")
224+ <> " bar")
225+ , "escaped auto link" =:
226+ "foo ~http://foo.example.com/bar/baz.html bar"
227+ =?> para "foo http://foo.example.com/bar/baz.html bar"
228+ , "wiki link simple" =:
229+ "foo [[http://foo.example.com/foo.png]] bar"
230+ =?> para ("foo "
231+ <> link "http://foo.example.com/foo.png" ""
232+ (str "http://foo.example.com/foo.png")
233+ <> " bar")
234+ , "wiki link with name" =:
235+ "foo [[http://foo.example.com/foo.png|my link]] bar"
236+ =?> para ("foo "
237+ <> link "http://foo.example.com/foo.png" ""
238+ (str "my link")
239+ <> " bar")
240+ , "image link" =:
241+ "[[http://foo.example.com/|{{foo.png}}]]"
242+ =?> para (link "http://foo.example.com/" "" (image "foo.png" "" (str "")))
243+ ]
244+ , testGroup "Table" [
245+ "Table with Header" =:
246+ T.unlines [ "|= Foo |= Bar |= Baz |"
247+ , "| One | Two | Three |"
248+ , "| 1 | 2 | 3 |"
249+ , "| A | B | C |"
250+ ]
251+ =?> simpleTable
252+ [plain "Foo", plain "Bar" , plain "Baz"]
253+ [[plain "One", plain "Two" , plain "Three"]
254+ ,[plain "1", plain "2" , plain "3"]
255+ ,[plain "A", plain "B" , plain "C"]]
256+ , "Table without Header" =:
257+ T.unlines [ "| One | Two | Three |"
258+ , "| 1 | 2 | 3 |"
259+ , "| A | B | C |"
260+ ]
261+ =?> simpleTable [mempty]
262+ [[plain "One", plain "Two" , plain "Three"]
263+ ,[plain "1", plain "2" , plain "3"]
264+ ,[plain "A", plain "B" , plain "C"]]
265+ , "Table without Header, no markers at line ends" =:
266+ T.unlines [ "| One | Two | Three"
267+ , "| 1 | 2 | 3"
268+ , "| A | B | C "
269+ ]
270+ =?> simpleTable [mempty]
271+ [[plain "One", plain "Two" , plain "Three"]
272+ ,[plain "1", plain "2" , plain "3"]
273+ ,[plain "A", plain "B" , plain "C"]]
274+ , "Table with Header, with formatting" =:
275+ T.unlines [ "|= **Foo** |= **Bar** |= **Baz** |"
276+ , "|//one// element |//second// elt|Three |"
277+ , "| {{{1}}} | {{{{}}}} | [[link]] |"
278+ ]
279+ =?> simpleTable
280+ [plain $ strong "Foo", plain $ strong "Bar" , plain $ strong "Baz"]
281+ [[plain (emph "one" <> " element"), plain (emph "second" <> " elt")
282+ ,plain "Three"]
283+ ,[plain $ code "1", plain $ code "{}"
284+ ,plain $ link "link" "" (str "link")]]
285+ ]
286+ ]
test/Tests/Readers/Docx.hs+14
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Readers.Docx (tests) where
23
4+import Prelude
35import Codec.Archive.Zip
46import qualified Data.ByteString as BS
57import qualified Data.ByteString.Lazy as B
@@ -178,6 +180,14 @@ tests = [ testGroup "inlines"
178180 "inlines inside of Structured Document Tags"
179181 "docx/sdt_elements.docx"
180182 "docx/sdt_elements.native"
183+ , testCompare
184+ "nested Structured Document Tags"
185+ "docx/nested_sdt.docx"
186+ "docx/nested_sdt.native"
187+ , testCompare
188+ "nested Smart Tags"
189+ "docx/nested_smart_tags.docx"
190+ "docx/nested_smart_tags.native"
181191 , testCompare
182192 "remove anchor spans with nothing pointing to them"
183193 "docx/unused_anchors.docx"
@@ -280,6 +290,10 @@ tests = [ testGroup "inlines"
280290 "code block"
281291 "docx/codeblock.docx"
282292 "docx/codeblock.native"
293+ , testCompare
294+ "combine adjacent code blocks"
295+ "docx/adjacent_codeblocks.docx"
296+ "docx/adjacent_codeblocks.native"
283297 , testCompare
284298 "dropcap paragraphs"
285299 "docx/drop_cap.docx"
test/Tests/Readers/Docx.hs.orignew file+405
@@ -0,0 +1,405 @@
1+module Tests.Readers.Docx (tests) where
2+
3+import Codec.Archive.Zip
4+import qualified Data.ByteString as BS
5+import qualified Data.ByteString.Lazy as B
6+import qualified Data.Map as M
7+import qualified Data.Text as T
8+import Data.Maybe
9+import System.IO.Unsafe
10+import Test.Tasty
11+import Test.Tasty.HUnit
12+import Tests.Helpers
13+import Text.Pandoc
14+import qualified Text.Pandoc.Class as P
15+import Text.Pandoc.MediaBag (MediaBag, lookupMedia, mediaDirectory)
16+import Text.Pandoc.UTF8 as UTF8
17+
18+-- We define a wrapper around pandoc that doesn't normalize in the
19+-- tests. Since we do our own normalization, we want to make sure
20+-- we're doing it right.
21+
22+data NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
23+ deriving Show
24+
25+noNorm :: Pandoc -> NoNormPandoc
26+noNorm = NoNormPandoc
27+
28+defopts :: ReaderOptions
29+defopts = def{ readerExtensions = getDefaultExtensions "docx" }
30+
31+instance ToString NoNormPandoc where
32+ toString d = T.unpack $ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
33+ where s = case d of
34+ NoNormPandoc (Pandoc (Meta m) _)
35+ | M.null m -> Nothing
36+ | otherwise -> Just "" -- need this to get meta output
37+
38+instance ToPandoc NoNormPandoc where
39+ toPandoc = unNoNorm
40+
41+compareOutput :: ReaderOptions
42+ -> FilePath
43+ -> FilePath
44+ -> IO (NoNormPandoc, NoNormPandoc)
45+compareOutput opts docxFile nativeFile = do
46+ df <- B.readFile docxFile
47+ nf <- UTF8.toText <$> BS.readFile nativeFile
48+ p <- runIOorExplode $ readDocx opts df
49+ df' <- runIOorExplode $ readNative def nf
50+ return (noNorm p, noNorm df')
51+
52+testCompareWithOptsIO :: ReaderOptions -> String -> FilePath -> FilePath -> IO TestTree
53+testCompareWithOptsIO opts name docxFile nativeFile = do
54+ (dp, np) <- compareOutput opts docxFile nativeFile
55+ return $ test id name (dp, np)
56+
57+testCompareWithOpts :: ReaderOptions -> String -> FilePath -> FilePath -> TestTree
58+testCompareWithOpts opts name docxFile nativeFile =
59+ unsafePerformIO $ testCompareWithOptsIO opts name docxFile nativeFile
60+
61+testCompare :: String -> FilePath -> FilePath -> TestTree
62+testCompare = testCompareWithOpts defopts
63+
64+testForWarningsWithOptsIO :: ReaderOptions -> String -> FilePath -> [String] -> IO TestTree
65+testForWarningsWithOptsIO opts name docxFile expected = do
66+ df <- B.readFile docxFile
67+ logs <- runIOorExplode $ setVerbosity ERROR >> readDocx opts df >> P.getLog
68+ let warns = [m | DocxParserWarning m <- logs]
69+ return $ test id name (unlines warns, unlines expected)
70+
71+testForWarningsWithOpts :: ReaderOptions -> String -> FilePath -> [String] -> TestTree
72+testForWarningsWithOpts opts name docxFile expected =
73+ unsafePerformIO $ testForWarningsWithOptsIO opts name docxFile expected
74+
75+-- testForWarnings :: String -> FilePath -> [String] -> TestTree
76+-- testForWarnings = testForWarningsWithOpts defopts
77+
78+getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
79+getMedia archivePath mediaPath = do
80+ zf <- B.readFile archivePath >>= return . toArchive
81+ return $ findEntryByPath ("word/" ++ mediaPath) zf >>= (Just . fromEntry)
82+
83+compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
84+compareMediaPathIO mediaPath mediaBag docxPath = do
85+ docxMedia <- getMedia docxPath mediaPath
86+ let mbBS = case lookupMedia mediaPath mediaBag of
87+ Just (_, bs) -> bs
88+ Nothing -> error ("couldn't find " ++
89+ mediaPath ++
90+ " in media bag")
91+ docxBS = fromMaybe (error ("couldn't find " ++
92+ mediaPath ++
93+ " in media bag")) docxMedia
94+ return $ mbBS == docxBS
95+
96+compareMediaBagIO :: FilePath -> IO Bool
97+compareMediaBagIO docxFile = do
98+ df <- B.readFile docxFile
99+ mb <- runIOorExplode $ readDocx defopts df >> P.getMediaBag
100+ bools <- mapM
101+ (\(fp, _, _) -> compareMediaPathIO fp mb docxFile)
102+ (mediaDirectory mb)
103+ return $ and bools
104+
105+testMediaBagIO :: String -> FilePath -> IO TestTree
106+testMediaBagIO name docxFile = do
107+ outcome <- compareMediaBagIO docxFile
108+ return $ testCase name (assertBool
109+ ("Media didn't match media bag in file " ++ docxFile)
110+ outcome)
111+
112+testMediaBag :: String -> FilePath -> TestTree
113+testMediaBag name docxFile = unsafePerformIO $ testMediaBagIO name docxFile
114+
115+tests :: [TestTree]
116+tests = [ testGroup "inlines"
117+ [ testCompare
118+ "font formatting"
119+ "docx/inline_formatting.docx"
120+ "docx/inline_formatting.native"
121+ , testCompare
122+ "font formatting with character styles"
123+ "docx/char_styles.docx"
124+ "docx/char_styles.native"
125+ , testCompare
126+ "hyperlinks"
127+ "docx/links.docx"
128+ "docx/links.native"
129+ , testCompare
130+ "hyperlinks in <w:instrText> tag"
131+ "docx/instrText_hyperlink.docx"
132+ "docx/instrText_hyperlink.native"
133+ , testCompare
134+ "inline image"
135+ "docx/image.docx"
136+ "docx/image_no_embed.native"
137+ , testCompare
138+ "VML image"
139+ "docx/image_vml.docx"
140+ "docx/image_vml.native"
141+ , testCompare
142+ "inline image in links"
143+ "docx/inline_images.docx"
144+ "docx/inline_images.native"
145+ , testCompare
146+ "handling unicode input"
147+ "docx/unicode.docx"
148+ "docx/unicode.native"
149+ , testCompare
150+ "literal tabs"
151+ "docx/tabs.docx"
152+ "docx/tabs.native"
153+ , testCompare
154+ "special punctuation"
155+ "docx/special_punctuation.docx"
156+ "docx/special_punctuation.native"
157+ , testCompare
158+ "normalizing inlines"
159+ "docx/normalize.docx"
160+ "docx/normalize.native"
161+ , testCompare
162+ "normalizing inlines deep inside blocks"
163+ "docx/deep_normalize.docx"
164+ "docx/deep_normalize.native"
165+ , testCompare
166+ "move trailing spaces outside of formatting"
167+ "docx/trailing_spaces_in_formatting.docx"
168+ "docx/trailing_spaces_in_formatting.native"
169+ , testCompare
170+ "inline code (with VerbatimChar style)"
171+ "docx/inline_code.docx"
172+ "docx/inline_code.native"
173+ , testCompare
174+ "inline code in subscript and superscript"
175+ "docx/verbatim_subsuper.docx"
176+ "docx/verbatim_subsuper.native"
177+ , testCompare
178+ "inlines inside of Structured Document Tags"
179+ "docx/sdt_elements.docx"
180+ "docx/sdt_elements.native"
181+ , testCompare
182+ "nested Structured Document Tags"
183+ "docx/nested_sdt.docx"
184+ "docx/nested_sdt.native"
185+ , testCompare
186+ "nested Smart Tags"
187+ "docx/nested_smart_tags.docx"
188+ "docx/nested_smart_tags.native"
189+ , testCompare
190+ "remove anchor spans with nothing pointing to them"
191+ "docx/unused_anchors.docx"
192+ "docx/unused_anchors.native"
193+ , testCompare
194+ "collapse overlapping targets (anchor spans)"
195+ "docx/overlapping_targets.docx"
196+ "docx/overlapping_targets.native"
197+ ]
198+ , testGroup "blocks"
199+ [ testCompare
200+ "headers"
201+ "docx/headers.docx"
202+ "docx/headers.native"
203+ , testCompare
204+ "headers already having auto identifiers"
205+ "docx/already_auto_ident.docx"
206+ "docx/already_auto_ident.native"
207+ , testCompare
208+ "avoid zero-level headers"
209+ "docx/0_level_headers.docx"
210+ "docx/0_level_headers.native"
211+ , testCompare
212+ "nested anchor spans in header"
213+ "docx/nested_anchors_in_header.docx"
214+ "docx/nested_anchors_in_header.native"
215+ , testCompare
216+ "single numbered item not made into list"
217+ "docx/numbered_header.docx"
218+ "docx/numbered_header.native"
219+ , testCompare
220+ "enumerated headers not made into numbered list"
221+ "docx/enumerated_headings.docx"
222+ "docx/enumerated_headings.native"
223+ , testCompare
224+ "i18n blocks (headers and blockquotes)"
225+ "docx/i18n_blocks.docx"
226+ "docx/i18n_blocks.native"
227+ , testCompare
228+ "lists"
229+ "docx/lists.docx"
230+ "docx/lists.native"
231+ , testCompare
232+ "lists continuing after interruption"
233+ "docx/lists_continuing.docx"
234+ "docx/lists_continuing.native"
235+ , testCompare
236+ "lists restarting after interruption"
237+ "docx/lists_restarting.docx"
238+ "docx/lists_restarting.native"
239+ , testCompare
240+ "definition lists"
241+ "docx/definition_list.docx"
242+ "docx/definition_list.native"
243+ , testCompare
244+ "custom defined lists in styles"
245+ "docx/german_styled_lists.docx"
246+ "docx/german_styled_lists.native"
247+ , testCompare
248+ "user deletes bullet after list item (=> part of item par)"
249+ "docx/dummy_item_after_list_item.docx"
250+ "docx/dummy_item_after_list_item.native"
251+ , testCompare
252+ "user deletes bullet after par (=> new par)"
253+ "docx/dummy_item_after_paragraph.docx"
254+ "docx/dummy_item_after_paragraph.native"
255+ , testCompare
256+ "footnotes and endnotes"
257+ "docx/notes.docx"
258+ "docx/notes.native"
259+ , testCompare
260+ "links in footnotes and endnotes"
261+ "docx/link_in_notes.docx"
262+ "docx/link_in_notes.native"
263+ , testCompare
264+ "blockquotes (parsing indent as blockquote)"
265+ "docx/block_quotes.docx"
266+ "docx/block_quotes_parse_indent.native"
267+ , testCompare
268+ "hanging indents"
269+ "docx/hanging_indent.docx"
270+ "docx/hanging_indent.native"
271+ , testCompare
272+ "tables"
273+ "docx/tables.docx"
274+ "docx/tables.native"
275+ , testCompare
276+ "tables with lists in cells"
277+ "docx/table_with_list_cell.docx"
278+ "docx/table_with_list_cell.native"
279+ , testCompare
280+ "tables with one row"
281+ "docx/table_one_row.docx"
282+ "docx/table_one_row.native"
283+ , testCompare
284+ "tables with variable width"
285+ "docx/table_variable_width.docx"
286+ "docx/table_variable_width.native"
287+ , testCompare
288+ "code block"
289+ "docx/codeblock.docx"
290+ "docx/codeblock.native"
291+ , testCompare
292+ "dropcap paragraphs"
293+ "docx/drop_cap.docx"
294+ "docx/drop_cap.native"
295+ ]
296+ , testGroup "track changes"
297+ [ testCompare
298+ "insertion (default)"
299+ "docx/track_changes_insertion.docx"
300+ "docx/track_changes_insertion_accept.native"
301+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
302+ "insert insertion (accept)"
303+ "docx/track_changes_insertion.docx"
304+ "docx/track_changes_insertion_accept.native"
305+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
306+ "remove insertion (reject)"
307+ "docx/track_changes_insertion.docx"
308+ "docx/track_changes_insertion_reject.native"
309+ , testCompare
310+ "deletion (default)"
311+ "docx/track_changes_deletion.docx"
312+ "docx/track_changes_deletion_accept.native"
313+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
314+ "remove deletion (accept)"
315+ "docx/track_changes_deletion.docx"
316+ "docx/track_changes_deletion_accept.native"
317+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
318+ "insert deletion (reject)"
319+ "docx/track_changes_deletion.docx"
320+ "docx/track_changes_deletion_reject.native"
321+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
322+ "keep insertion (all)"
323+ "docx/track_changes_deletion.docx"
324+ "docx/track_changes_deletion_all.native"
325+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
326+ "keep deletion (all)"
327+ "docx/track_changes_deletion.docx"
328+ "docx/track_changes_deletion_all.native"
329+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
330+ "move text (accept)"
331+ "docx/track_changes_move.docx"
332+ "docx/track_changes_move_accept.native"
333+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
334+ "move text (reject)"
335+ "docx/track_changes_move.docx"
336+ "docx/track_changes_move_reject.native"
337+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
338+ "move text (all)"
339+ "docx/track_changes_move.docx"
340+ "docx/track_changes_move_all.native"
341+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
342+ "comments (accept -- no comments)"
343+ "docx/comments.docx"
344+ "docx/comments_no_comments.native"
345+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
346+ "comments (reject -- comments)"
347+ "docx/comments.docx"
348+ "docx/comments_no_comments.native"
349+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
350+ "comments (all comments)"
351+ "docx/comments.docx"
352+ "docx/comments.native"
353+ , testCompareWithOpts def{readerTrackChanges=AcceptChanges}
354+ "paragraph insertion/deletion (accept)"
355+ "docx/paragraph_insertion_deletion.docx"
356+ "docx/paragraph_insertion_deletion_accept.native"
357+ , testCompareWithOpts def{readerTrackChanges=RejectChanges}
358+ "paragraph insertion/deletion (reject)"
359+ "docx/paragraph_insertion_deletion.docx"
360+ "docx/paragraph_insertion_deletion_reject.native"
361+ , testCompareWithOpts def{readerTrackChanges=AllChanges}
362+ "paragraph insertion/deletion (all)"
363+ "docx/paragraph_insertion_deletion.docx"
364+ "docx/paragraph_insertion_deletion_all.native"
365+ , testForWarningsWithOpts def{readerTrackChanges=AcceptChanges}
366+ "comment warnings (accept -- no warnings)"
367+ "docx/comments_warning.docx"
368+ []
369+ , testForWarningsWithOpts def{readerTrackChanges=RejectChanges}
370+ "comment warnings (reject -- no warnings)"
371+ "docx/comments_warning.docx"
372+ []
373+ , testForWarningsWithOpts def{readerTrackChanges=AllChanges}
374+ "comment warnings (all)"
375+ "docx/comments_warning.docx"
376+ ["Docx comment 1 will not retain formatting"]
377+ ]
378+ , testGroup "media"
379+ [ testMediaBag
380+ "image extraction"
381+ "docx/image.docx"
382+ ]
383+ , testGroup "custom styles"
384+ [ testCompare
385+ "custom styles (`+styles`) not enabled (default)"
386+ "docx/custom-style-reference.docx"
387+ "docx/custom-style-no-styles.native"
388+ , testCompareWithOpts
389+ def{readerExtensions=extensionsFromList [Ext_styles]}
390+ "custom styles (`+styles`) enabled"
391+ "docx/custom-style-reference.docx"
392+ "docx/custom-style-with-styles.native"
393+ ]
394+ , testGroup "metadata"
395+ [ testCompareWithOpts def{readerStandalone=True}
396+ "metadata fields"
397+ "docx/metadata.docx"
398+ "docx/metadata.native"
399+ , testCompareWithOpts def{readerStandalone=True}
400+ "stop recording metadata with normal text"
401+ "docx/metadata_after_normal.docx"
402+ "docx/metadata_after_normal.native"
403+ ]
404+
405+ ]
test/Tests/Readers/EPUB.hs+2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Readers.EPUB (tests) where
23
4+import Prelude
35import qualified Data.ByteString.Lazy as BL
46import Test.Tasty
57import Test.Tasty.HUnit
test/Tests/Readers/EPUB.hs.orignew file+40
@@ -0,0 +1,40 @@
1+module Tests.Readers.EPUB (tests) where
2+
3+import qualified Data.ByteString.Lazy as BL
4+import Test.Tasty
5+import Test.Tasty.HUnit
6+import qualified Text.Pandoc.Class as P
7+import Text.Pandoc.MediaBag (MediaBag, mediaDirectory)
8+import Text.Pandoc.Options
9+import Text.Pandoc.Readers.EPUB
10+
11+getMediaBag :: FilePath -> IO MediaBag
12+getMediaBag fp = do
13+ bs <- BL.readFile fp
14+ P.runIOorExplode $ do
15+ readEPUB def bs
16+ P.getMediaBag
17+
18+testMediaBag :: FilePath -> [(String, String, Int)] -> IO ()
19+testMediaBag fp bag = do
20+ actBag <- mediaDirectory <$> getMediaBag fp
21+ assertBool (show "MediaBag did not match:\nExpected: "
22+ ++ show bag
23+ ++ "\nActual: "
24+ ++ show actBag)
25+ (actBag == bag)
26+
27+featuresBag :: [(String, String, Int)]
28+featuresBag = [("img/check.gif","image/gif",1340)
29+ ,("img/check.jpg","image/jpeg",2661)
30+ ,("img/check.png","image/png",2815)
31+ ,("img/multiscripts_and_greek_alphabet.png","image/png",10060)
32+ ]
33+
34+tests :: [TestTree]
35+tests =
36+ [ testGroup "EPUB Mediabag"
37+ [ testCase "features bag"
38+ (testMediaBag "epub/img.epub" featuresBag)
39+ ]
40+ ]
test/Tests/Readers/FB2.hsnew file+29
@@ -0,0 +1,29 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+
3+module Tests.Readers.FB2 (tests) where
4+
5+import Prelude
6+import Test.Tasty
7+import Tests.Helpers
8+import Test.Tasty.Golden (goldenVsString)
9+import qualified Data.ByteString as BS
10+import Text.Pandoc
11+import Text.Pandoc.UTF8 (toText, fromTextLazy)
12+import Data.Text (Text)
13+import Data.Text.Lazy (fromStrict)
14+import System.FilePath (replaceExtension)
15+
16+fb2ToNative :: Text -> Text
17+fb2ToNative = purely (writeNative def{ writerTemplate = Just "" }) . purely (readFB2 def)
18+
19+fb2Test :: TestName -> FilePath -> TestTree
20+fb2Test name path = goldenVsString name native (fromTextLazy . fromStrict . fb2ToNative . toText <$> BS.readFile path)
21+ where native = replaceExtension path ".native"
22+
23+tests :: [TestTree]
24+tests = [ fb2Test "Emphasis" "fb2/reader/emphasis.fb2"
25+ , fb2Test "Titles" "fb2/reader/titles.fb2"
26+ , fb2Test "Epigraph" "fb2/reader/epigraph.fb2"
27+ , fb2Test "Poem" "fb2/reader/poem.fb2"
28+ , fb2Test "Meta" "fb2/reader/meta.fb2"
29+ ]
test/Tests/Readers/HTML.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.HTML (tests) where
34
5+import Prelude
46import Data.Text (Text)
57import Test.Tasty
68import Tests.Helpers
test/Tests/Readers/HTML.hs.orignew file+54
@@ -0,0 +1,54 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.HTML (tests) where
3+
4+import Data.Text (Text)
5+import Test.Tasty
6+import Tests.Helpers
7+import Text.Pandoc
8+import Text.Pandoc.Arbitrary ()
9+import Text.Pandoc.Builder
10+
11+html :: Text -> Pandoc
12+html = purely $ readHtml def
13+
14+htmlNativeDivs :: Text -> Pandoc
15+htmlNativeDivs = purely $ readHtml def { readerExtensions = enableExtension Ext_native_divs $ readerExtensions def }
16+
17+tests :: [TestTree]
18+tests = [ testGroup "base tag"
19+ [ test html "simple" $
20+ "<head><base href=\"http://www.w3schools.com/images/foo\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
21+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
22+ , test html "slash at end of base" $
23+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"stickman.gif\" alt=\"Stickman\"></head>" =?>
24+ plain (image "http://www.w3schools.com/images/stickman.gif" "" (text "Stickman"))
25+ , test html "slash at beginning of href" $
26+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"/stickman.gif\" alt=\"Stickman\"></head>" =?>
27+ plain (image "http://www.w3schools.com/stickman.gif" "" (text "Stickman"))
28+ , test html "absolute URL" $
29+ "<head><base href=\"http://www.w3schools.com/images/\" ></head><body><img src=\"http://example.com/stickman.gif\" alt=\"Stickman\"></head>" =?>
30+ plain (image "http://example.com/stickman.gif" "" (text "Stickman"))
31+ ]
32+ , testGroup "anchors"
33+ [ test html "anchor without href" $ "<a name=\"anchor\"/>" =?>
34+ plain (spanWith ("anchor",[],[]) mempty)
35+ ]
36+ , testGroup "lang"
37+ [ test html "lang on <html>" $ "<html lang=\"es\">hola" =?>
38+ setMeta "lang" (text "es") (doc (plain (text "hola")))
39+ , test html "xml:lang on <html>" $ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"es\"><head></head><body>hola</body></html>" =?>
40+ setMeta "lang" (text "es") (doc (plain (text "hola")))
41+ ]
42+ , testGroup "main"
43+ [ test htmlNativeDivs "<main> becomes <div role=main>" $ "<main>hello</main>" =?>
44+ doc (divWith ("", [], [("role", "main")]) (plain (text "hello")))
45+ , test htmlNativeDivs "<main role=X> becomes <div role=X>" $ "<main role=foobar>hello</main>" =?>
46+ doc (divWith ("", [], [("role", "foobar")]) (plain (text "hello")))
47+ , test htmlNativeDivs "<main> has attributes preserved" $ "<main id=foo class=bar data-baz=qux>hello</main>" =?>
48+ doc (divWith ("foo", ["bar"], [("role", "main"), ("data-baz", "qux")]) (plain (text "hello")))
49+ , test htmlNativeDivs "<main> closes <p>" $ "<p>hello<main>main content</main>" =?>
50+ doc (para (text "hello") <> divWith ("", [], [("role", "main")]) (plain (text "main content")))
51+ , test htmlNativeDivs "<main> followed by text" $ "<main>main content</main>non-main content" =?>
52+ doc (divWith ("", [], [("role", "main")]) (plain (text "main content")) <> plain (text "non-main content"))
53+ ]
54+ ]
test/Tests/Readers/JATS.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.JATS (tests) where
34
5+import Prelude
46import Data.Text (Text)
57import Test.Tasty
68import Tests.Helpers
test/Tests/Readers/JATS.hs.orignew file+116
@@ -0,0 +1,116 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.JATS (tests) where
3+
4+import Data.Text (Text)
5+import Test.Tasty
6+import Tests.Helpers
7+import Text.Pandoc
8+import Text.Pandoc.Arbitrary ()
9+import Text.Pandoc.Builder
10+
11+jats :: Text -> Pandoc
12+jats = purely $ readJATS def
13+
14+tests :: [TestTree]
15+tests = [ testGroup "inline code"
16+ [ test jats "basic" $ "<p>\n <monospace>@&amp;</monospace>\n</p>" =?> para (code "@&")
17+ , test jats "lang" $ "<p>\n <code language=\"c\">@&amp;</code>\n</p>" =?> para (codeWith ("", ["c"], []) "@&")
18+ ]
19+ , testGroup "block code"
20+ [ test jats "basic" $ "<preformat>@&amp;</preformat>" =?> codeBlock "@&"
21+ , test jats "lang" $ "<code language=\"c\">@&amp;</code>" =?> codeBlockWith ("", ["c"], []) "@&"
22+ ]
23+ , testGroup "images"
24+ [ test jats "basic" $ "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
25+ =?> para (image "/url" "title" mempty)
26+ ]
27+ , test jats "bullet list" $
28+ "<list list-type=\"bullet\">\n\
29+ \ <list-item>\n\
30+ \ <p>\n\
31+ \ first\n\
32+ \ </p>\n\
33+ \ </list-item>\n\
34+ \ <list-item>\n\
35+ \ <p>\n\
36+ \ second\n\
37+ \ </p>\n\
38+ \ </list-item>\n\
39+ \ <list-item>\n\
40+ \ <p>\n\
41+ \ third\n\
42+ \ </p>\n\
43+ \ </list-item>\n\
44+ \</list>"
45+ =?> bulletList [ para $ text "first"
46+ , para $ text "second"
47+ , para $ text "third"
48+ ]
49+ , testGroup "definition lists"
50+ [ test jats "with internal link" $
51+ "<def-list>\n\
52+ \ <def-item>\n\
53+ \ <term>\n\
54+ \ <xref alt=\"testing\" rid=\"go\">testing</xref>\n\
55+ \ </term>\n\
56+ \ <def>\n\
57+ \ <p>\n\
58+ \ hi there\n\
59+ \ </p>\n\
60+ \ </def>\n\
61+ \ </def-item>\n\
62+ \</def-list>"
63+ =?> definitionList [(link "#go" "" (str "testing"),
64+ [para (text "hi there")])]
65+ ]
66+ , testGroup "math"
67+ [ test jats "escape |" $
68+ "<p>\n\
69+ \ <inline-formula><alternatives>\n\
70+ \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
71+ \ <mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>\n\
72+ \</p>"
73+ =?> para (math "\\sigma|_{\\{x\\}}")
74+ , test jats "tex-math only" $
75+ "<p>\n\
76+ \ <inline-formula><alternatives>\n\
77+ \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
78+ \</p>"
79+ =?> para (math "\\sigma|_{\\{x\\}}")
80+ , test jats "math ml only" $
81+ "<p>\n\
82+ \ <inline-formula><alternatives>\n\
83+ \ <mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>\n\
84+ \</p>"
85+ =?> para (math "\\sigma|_{\\{ x\\}}")
86+ ]
87+ , testGroup "headers"
88+-- TODO fix footnotes in headers
89+-- [ test jats "unnumbered header" $
90+-- "<sec>\n\
91+-- \ <title>Header 1<fn>\n\
92+-- \ <p>\n\
93+-- \ note\n\
94+-- \ </p>\n\
95+-- \ </fn></title>\n\
96+-- \</sec>"
97+-- =?> header 1
98+-- (text "Header 1" <> note (plain $ text "note"))
99+ [ test jats "unnumbered sub header" $
100+ "<sec id=\"foo\">\n\
101+ \ <title>Header</title>\n\
102+ \ <sec id=\"foo2\">\n\
103+ \ <title>Sub-Header</title>\n\
104+ \ </sec>\n\
105+ \</sec>"
106+ =?> headerWith ("foo", [], []) 1
107+ (text "Header")
108+ <> headerWith ("foo2", [], []) 2
109+ (text "Sub-Header")
110+ , test jats "containing image" $
111+ "<sec>\n\
112+ \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
113+ \</sec>"
114+ =?> header 1 (image "imgs/foo.jpg" "" mempty)
115+ ]
116+ ]
test/Tests/Readers/LaTeX.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.LaTeX (tests) where
34
5+import Prelude
46import Data.Text (Text)
57import qualified Data.Text as T
68import qualified Text.Pandoc.UTF8 as UTF8
test/Tests/Readers/LaTeX.hs.orignew file+341
@@ -0,0 +1,341 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.LaTeX (tests) where
3+
4+import Data.Text (Text)
5+import qualified Data.Text as T
6+import qualified Text.Pandoc.UTF8 as UTF8
7+import Text.Pandoc.Readers.LaTeX (tokenize, untokenize)
8+import Test.Tasty
9+import Test.Tasty.HUnit
10+import Test.Tasty.QuickCheck
11+import Tests.Helpers
12+import Text.Pandoc
13+import Text.Pandoc.Arbitrary ()
14+import Text.Pandoc.Builder
15+
16+latex :: Text -> Pandoc
17+latex = purely $ readLaTeX def{
18+ readerExtensions = getDefaultExtensions "latex" }
19+
20+infix 4 =:
21+(=:) :: ToString c
22+ => String -> (Text, c) -> TestTree
23+(=:) = test latex
24+
25+simpleTable' :: [Alignment] -> [[Blocks]] -> Blocks
26+simpleTable' aligns = table "" (zip aligns (repeat 0.0))
27+ (map (const mempty) aligns)
28+
29+tokUntokRt :: String -> Bool
30+tokUntokRt s = untokenize (tokenize "random" t) == t
31+ where t = T.pack s
32+
33+tests :: [TestTree]
34+tests = [ testGroup "tokenization"
35+ [ testCase "tokenizer round trip on test case" $ do
36+ orig <- T.pack <$> UTF8.readFile "../test/latex-reader.latex"
37+ let new = untokenize $ tokenize "../test/latex-reader.latex"
38+ orig
39+ assertEqual "untokenize . tokenize is identity" orig new
40+ , testProperty "untokenize . tokenize is identity" tokUntokRt
41+ ]
42+
43+ , testGroup "basic"
44+ [ "simple" =:
45+ "word" =?> para "word"
46+ , "space" =:
47+ "some text" =?> para "some text"
48+ , "emphasized" =:
49+ "\\emph{emphasized}" =?> para (emph "emphasized")
50+ ]
51+
52+ , testGroup "headers"
53+ [ "level 1" =:
54+ "\\section{header}" =?> headerWith ("header",[],[]) 1 "header"
55+ , "level 2" =:
56+ "\\subsection{header}" =?> headerWith ("header",[],[]) 2 "header"
57+ , "level 3" =:
58+ "\\subsubsection{header}" =?> headerWith ("header",[],[]) 3 "header"
59+ , "emph" =:
60+ "\\section{text \\emph{emph}}" =?>
61+ headerWith ("text-emph",[],[]) 1 ("text" <> space <> emph "emph")
62+ , "link" =:
63+ "\\section{text \\href{/url}{link}}" =?>
64+ headerWith ("text-link",[],[]) 1 ("text" <> space <> link "/url" "" "link")
65+ ]
66+
67+ , testGroup "math"
68+ [ "escaped $" =:
69+ "$x=\\$4$" =?> para (math "x=\\$4")
70+ ]
71+
72+ , testGroup "space and comments"
73+ [ "blank lines + space at beginning" =:
74+ "\n \n hi" =?> para "hi"
75+ , "blank lines + space + comments" =:
76+ "% my comment\n\n \n % another\n\nhi" =?> para "hi"
77+ , "comment in paragraph" =:
78+ "hi % this is a comment\nthere\n" =?>
79+ para ("hi" <> softbreak <> "there")
80+ ]
81+
82+ , testGroup "code blocks"
83+ [ "identifier" =:
84+ "\\begin{lstlisting}[label=test]\\end{lstlisting}" =?> codeBlockWith ("test", [], [("label","test")]) ""
85+ , "no identifier" =:
86+ "\\begin{lstlisting}\\end{lstlisting}" =?> codeBlock ""
87+ ]
88+
89+ , testGroup "tables"
90+ [ "Single cell table" =:
91+ "\\begin{tabular}{|l|}Test\\\\\\end{tabular}" =?>
92+ simpleTable' [AlignLeft] [[plain "Test"]]
93+ , "Multi cell table" =:
94+ "\\begin{tabular}{|rl|}One & Two\\\\ \\end{tabular}" =?>
95+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
96+ , "Multi line table" =:
97+ T.unlines [ "\\begin{tabular}{|c|}"
98+ , "One\\\\"
99+ , "Two\\\\"
100+ , "Three\\\\"
101+ , "\\end{tabular}" ] =?>
102+ simpleTable' [AlignCenter]
103+ [[plain "One"], [plain "Two"], [plain "Three"]]
104+ , "Empty table" =:
105+ "\\begin{tabular}{}\\end{tabular}" =?>
106+ simpleTable' [] []
107+ , "Table with fixed column width" =:
108+ "\\begin{tabular}{|p{5cm}r|}One & Two\\\\ \\end{tabular}" =?>
109+ simpleTable' [AlignLeft,AlignRight] [[plain "One", plain "Two"]]
110+ , "Table with empty column separators" =:
111+ "\\begin{tabular}{@{}r@{}l}One & Two\\\\ \\end{tabular}" =?>
112+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
113+ , "Table with custom column separators" =:
114+ T.unlines [ "\\begin{tabular}{@{($\\to$)}r@{\\hspace{2cm}}l}"
115+ , "One&Two\\\\"
116+ , "\\end{tabular}" ] =?>
117+ simpleTable' [AlignRight,AlignLeft] [[plain "One", plain "Two"]]
118+ , "Table with vertical alignment argument" =:
119+ "\\begin{tabular}[t]{r|r}One & Two\\\\ \\end{tabular}" =?>
120+ simpleTable' [AlignRight,AlignRight] [[plain "One", plain "Two"]]
121+ ]
122+
123+ , testGroup "citations"
124+ [ natbibCitations
125+ , biblatexCitations
126+ ]
127+
128+ , testGroup "images"
129+ [ "Basic image" =:
130+ "\\includegraphics{foo.png}" =?>
131+ para (image "foo.png" "" (text "image"))
132+ , "Basic image with blank options" =:
133+ "\\includegraphics[]{foo.png}" =?>
134+ para (image "foo.png" "" (text "image"))
135+ , "Image with both width and height" =:
136+ "\\includegraphics[width=17cm,height=5cm]{foo.png}" =?>
137+ para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image")
138+ , "Image with width and height and a bunch of other options" =:
139+ "\\includegraphics[width=17cm,height=5cm,clip,keepaspectratio]{foo.png}" =?>
140+ para (imageWith ("", [], [("width", "17cm"), ("height", "5cm")]) "foo.png" "" "image")
141+ , "Image with just width" =:
142+ "\\includegraphics[width=17cm]{foo.png}" =?>
143+ para (imageWith ("", [], [("width", "17cm")]) "foo.png" "" "image")
144+ , "Image with just height" =:
145+ "\\includegraphics[height=17cm]{foo.png}" =?>
146+ para (imageWith ("", [], [("height", "17cm")]) "foo.png" "" "image")
147+ , "Image width relative to textsize" =:
148+ "\\includegraphics[width=0.6\\textwidth]{foo.png}" =?>
149+ para (imageWith ("", [], [("width", "60%")]) "foo.png" "" "image")
150+ , "Image with options with spaces" =:
151+ "\\includegraphics[width=12cm, height = 5cm]{foo.png}" =?>
152+ para (imageWith ("", [], [("width", "12cm"), ("height", "5cm")]) "foo.png" "" "image")
153+ ]
154+
155+ , let hex = ['0'..'9']++['a'..'f'] in
156+ testGroup "Character Escapes"
157+ [ "Two-character escapes" =:
158+ mconcat ["^^" <> T.pack [i,j] | i <- hex, j <- hex] =?>
159+ para (str ['\0'..'\255'])
160+ , "One-character escapes" =:
161+ mconcat ["^^" <> T.pack [i] | i <- hex] =?>
162+ para (str $ ['p'..'y']++['!'..'&'])
163+ ]
164+ , testGroup "memoir scene breaks"
165+ [ "plainbreak" =:
166+ "hello\\plainbreak{2}goodbye" =?>
167+ para (str "hello") <> horizontalRule <> para (str "goodbye")
168+ , "plainbreak*" =:
169+ "hello\\plainbreak*{2}goodbye" =?>
170+ para (str "hello") <> horizontalRule <> para (str "goodbye")
171+ , "fancybreak" =:
172+ "hello\\fancybreak{b r e a k}goodbye" =?>
173+ para (str "hello") <> horizontalRule <> para (str "goodbye")
174+ , "fancybreak*" =:
175+ "hello\\fancybreak*{b r e a k}goodbye" =?>
176+ para (str "hello") <> horizontalRule <> para (str "goodbye")
177+ , "plainfancybreak" =:
178+ "hello\\plainfancybreak{4}{2}{b r e a k}goodbye" =?>
179+ para (str "hello") <> horizontalRule <> para (str "goodbye")
180+ , "plainfancybreak*" =:
181+ "hello\\plainfancybreak*{4}{2}{b r e a k}goodbye" =?>
182+ para (str "hello") <> horizontalRule <> para (str "goodbye")
183+ , "pfbreak" =:
184+ "hello\\pfbreak{}goodbye" =?>
185+ para (str "hello") <> horizontalRule <> para (str "goodbye")
186+ , "pfbreak*" =:
187+ "hello\\pfbreak*{}goodbye" =?>
188+ para (str "hello") <> horizontalRule <> para (str "goodbye")
189+ ]
190+ , testGroup "biblatex roman numerals"
191+ [ "upper" =:
192+ "number \\RN{12}" =?>
193+ para (str "number" <> space <> str "XII")
194+ , "lower" =:
195+ "number \\Rn{29}" =?>
196+ para (str "number" <> space <> str "xxix")
197+ , "leading zero" =:
198+ "\\Rn{014}" =?>
199+ para (str "xiv")
200+ , "surrounding spaces" =:
201+ "number \\Rn{ 41 }" =?>
202+ para (str "number" <> space <> str "xli")
203+ , "zero" =:
204+ "\\RN{0}" =?>
205+ para (str "")
206+ , "space then unbraced argument" =:
207+ "\\RN 7 ok" =?>
208+ para (str "VII" <> space <> str "ok")
209+ , "space before braced argument" =:
210+ "\\Rn {13}ok" =?>
211+ para (str "xiiiok")
212+ ]
213+ , testGroup "polyglossia language spans"
214+ [ "french" =:
215+ "hello \\textfrench{bonjour}" =?>
216+ para (str "hello" <> space <> spanWith ("", [], [("lang", "fr")]) (str "bonjour"))
217+ , "nested" =:
218+ "\\textfrench{quelle c'est \\textlatin{primus}?}" =?>
219+ para (spanWith ("", [], [("lang", "fr")]) $
220+ str "quelle" <> space <> str "c\8217est" <> space <>
221+ spanWith ("", [], [("lang", "la")]) (str "primus") <> str "?")
222+ , "with formatting" =:
223+ "\\textgerman{wie \\emph{spaet} ist es?}" =?>
224+ para (spanWith ("", [], [("lang", "de")]) $
225+ str "wie" <> space <> emph (str "spaet") <> space <> str "ist" <> space <> str "es?")
226+ , "language options" =:
227+ "\\textgerman[variant=swiss]{hoechdeutsche}" =?>
228+ para (spanWith ("", [], [("lang", "de-CH")]) $ str "hoechdeutsche")
229+ , "unknown option fallback" =:
230+ "\\textgerman[variant=moon]{ueberhoechdeutsche}" =?>
231+ para (spanWith ("", [], [("lang", "de")]) $ str "ueberhoechdeutsche")
232+ ]
233+ ]
234+
235+baseCitation :: Citation
236+baseCitation = Citation{ citationId = "item1"
237+ , citationPrefix = []
238+ , citationSuffix = []
239+ , citationMode = AuthorInText
240+ , citationNoteNum = 0
241+ , citationHash = 0
242+ }
243+
244+rt :: String -> Inlines
245+rt = rawInline "latex"
246+
247+natbibCitations :: TestTree
248+natbibCitations = testGroup "natbib"
249+ [ "citet" =: "\\citet{item1}"
250+ =?> para (cite [baseCitation] (rt "\\citet{item1}"))
251+ , "suffix" =: "\\citet[p.~30]{item1}"
252+ =?> para
253+ (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\citet[p.~30]{item1}"))
254+ , "suffix long" =: "\\citet[p.~30, with suffix]{item1}"
255+ =?> para (cite [baseCitation{ citationSuffix =
256+ toList $ text "p.\160\&30, with suffix" }] (rt "\\citet[p.~30, with suffix]{item1}"))
257+ , "multiple" =: "\\citeauthor{item1} \\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"
258+ =?> para (cite [baseCitation{ citationMode = AuthorInText }
259+ ,baseCitation{ citationMode = SuppressAuthor
260+ , citationSuffix = [Str "p.\160\&30"]
261+ , citationId = "item2" }
262+ ,baseCitation{ citationId = "item3"
263+ , citationPrefix = [Str "see",Space,Str "also"]
264+ , citationMode = NormalCitation }
265+ ] (rt "\\citetext{\\citeyear{item1}; \\citeyear[p.~30]{item2}; \\citealp[see also][]{item3}}"))
266+ , "group" =: "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"
267+ =?> para (cite [baseCitation{ citationMode = NormalCitation
268+ , citationPrefix = [Str "see"]
269+ , citationSuffix = [Str "p.\160\&34\8211\&35"] }
270+ ,baseCitation{ citationMode = NormalCitation
271+ , citationId = "item3"
272+ , citationPrefix = [Str "also"]
273+ , citationSuffix = [Str "chap.",Space,Str "3"] }
274+ ] (rt "\\citetext{\\citealp[see][p.~34--35]{item1}; \\citealp[also][chap. 3]{item3}}"))
275+ , "suffix and locator" =: "\\citep[pp.~33, 35--37, and nowhere else]{item1}"
276+ =?> para (cite [baseCitation{ citationMode = NormalCitation
277+ , citationSuffix = [Str "pp.\160\&33,",Space,Str "35\8211\&37,",Space,Str "and",Space,Str "nowhere",Space, Str "else"] }] (rt "\\citep[pp.~33, 35--37, and nowhere else]{item1}"))
278+ , "suffix only" =: "\\citep[and nowhere else]{item1}"
279+ =?> para (cite [baseCitation{ citationMode = NormalCitation
280+ , citationSuffix = toList $ text "and nowhere else" }] (rt "\\citep[and nowhere else]{item1}"))
281+ , "no author" =: "\\citeyearpar{item1}, and now Doe with a locator \\citeyearpar[p.~44]{item2}"
282+ =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\citeyearpar{item1}") <>
283+ text ", and now Doe with a locator " <>
284+ cite [baseCitation{ citationMode = SuppressAuthor
285+ , citationSuffix = [Str "p.\160\&44"]
286+ , citationId = "item2" }] (rt "\\citeyearpar[p.~44]{item2}"))
287+ , "markup" =: "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"
288+ =?> para (cite [baseCitation{ citationMode = NormalCitation
289+ , citationPrefix = [Emph [Str "see"]]
290+ , citationSuffix = [Str "p.",Space,
291+ Strong [Str "32"]] }] (rt "\\citep[\\emph{see}][p. \\textbf{32}]{item1}"))
292+ ]
293+
294+biblatexCitations :: TestTree
295+biblatexCitations = testGroup "biblatex"
296+ [ "textcite" =: "\\textcite{item1}"
297+ =?> para (cite [baseCitation] (rt "\\textcite{item1}"))
298+ , "suffix" =: "\\textcite[p.~30]{item1}"
299+ =?> para
300+ (cite [baseCitation{ citationSuffix = toList $ text "p.\160\&30" }] (rt "\\textcite[p.~30]{item1}"))
301+ , "suffix long" =: "\\textcite[p.~30, with suffix]{item1}"
302+ =?> para (cite [baseCitation{ citationSuffix =
303+ toList $ text "p.\160\&30, with suffix" }] (rt "\\textcite[p.~30, with suffix]{item1}"))
304+ , "multiple" =: "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"
305+ =?> para (cite [baseCitation{ citationMode = AuthorInText }
306+ ,baseCitation{ citationMode = NormalCitation
307+ , citationSuffix = [Str "p.\160\&30"]
308+ , citationId = "item2" }
309+ ,baseCitation{ citationId = "item3"
310+ , citationPrefix = [Str "see",Space,Str "also"]
311+ , citationMode = NormalCitation }
312+ ] (rt "\\textcites{item1}[p.~30]{item2}[see also][]{item3}"))
313+ , "group" =: "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"
314+ =?> para (cite [baseCitation{ citationMode = NormalCitation
315+ , citationPrefix = [Str "see"]
316+ , citationSuffix = [Str "p.\160\&34\8211\&35"] }
317+ ,baseCitation{ citationMode = NormalCitation
318+ , citationId = "item3"
319+ , citationPrefix = [Str "also"]
320+ , citationSuffix = [Str "chap.",Space,Str "3"] }
321+ ] (rt "\\autocites[see][p.~34--35]{item1}[also][chap. 3]{item3}"))
322+ , "suffix and locator" =: "\\autocite[pp.~33, 35--37, and nowhere else]{item1}"
323+ =?> para (cite [baseCitation{ citationMode = NormalCitation
324+ , citationSuffix = [Str "pp.\160\&33,",Space,Str "35\8211\&37,",Space,Str "and",Space,Str "nowhere",Space, Str "else"] }] (rt "\\autocite[pp.~33, 35--37, and nowhere else]{item1}"))
325+ , "suffix only" =: "\\autocite[and nowhere else]{item1}"
326+ =?> para (cite [baseCitation{ citationMode = NormalCitation
327+ , citationSuffix = toList $ text "and nowhere else" }] (rt "\\autocite[and nowhere else]{item1}"))
328+ , "no author" =: "\\autocite*{item1}, and now Doe with a locator \\autocite*[p.~44]{item2}"
329+ =?> para (cite [baseCitation{ citationMode = SuppressAuthor }] (rt "\\autocite*{item1}") <>
330+ text ", and now Doe with a locator " <>
331+ cite [baseCitation{ citationMode = SuppressAuthor
332+ , citationSuffix = [Str "p.\160\&44"]
333+ , citationId = "item2" }] (rt "\\autocite*[p.~44]{item2}"))
334+ , "markup" =: "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"
335+ =?> para (cite [baseCitation{ citationMode = NormalCitation
336+ , citationPrefix = [Emph [Str "see"]]
337+ , citationSuffix = [Str "p.",Space,
338+ Strong [Str "32"]] }] (rt "\\autocite[\\emph{see}][p. \\textbf{32}]{item1}"))
339+ , "parencite" =: "\\parencite{item1}"
340+ =?> para (cite [baseCitation{ citationMode = NormalCitation }] (rt "\\parencite{item1}"))
341+ ]
test/Tests/Readers/Markdown.hs+5
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Markdown (tests) where
34
5+import Prelude
46import Data.Text (Text, unpack)
57import qualified Data.Text as T
68import Test.Tasty
@@ -293,6 +295,9 @@ tests = [ testGroup "inline code"
293295 , test markdownSmart "apostrophe after math" $ -- issue #1909
294296 "The value of the $x$'s and the systems' condition." =?>
295297 para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
298+ , test markdownSmart "unclosed double quote"
299+ ("**this should \"be bold**"
300+ =?> para (strong "this should \"be bold"))
296301 ]
297302 , testGroup "footnotes"
298303 [ "indent followed by newline and flush-left text" =:
test/Tests/Readers/Markdown.hs.orignew file+462
@@ -0,0 +1,462 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Markdown (tests) where
3+
4+import Data.Text (Text, unpack)
5+import qualified Data.Text as T
6+import Test.Tasty
7+import Tests.Helpers
8+import Text.Pandoc
9+import Text.Pandoc.Arbitrary ()
10+import Text.Pandoc.Builder
11+
12+markdown :: Text -> Pandoc
13+markdown = purely $ readMarkdown def { readerExtensions =
14+ disableExtension Ext_smart pandocExtensions }
15+
16+markdownSmart :: Text -> Pandoc
17+markdownSmart = purely $ readMarkdown def { readerExtensions =
18+ enableExtension Ext_smart pandocExtensions }
19+
20+markdownCDL :: Text -> Pandoc
21+markdownCDL = purely $ readMarkdown def { readerExtensions = enableExtension
22+ Ext_compact_definition_lists pandocExtensions }
23+
24+markdownGH :: Text -> Pandoc
25+markdownGH = purely $ readMarkdown def {
26+ readerExtensions = githubMarkdownExtensions }
27+
28+infix 4 =:
29+(=:) :: ToString c
30+ => String -> (Text, c) -> TestTree
31+(=:) = test markdown
32+
33+testBareLink :: (Text, Inlines) -> TestTree
34+testBareLink (inp, ils) =
35+ test (purely $ readMarkdown def{ readerExtensions =
36+ extensionsFromList [Ext_autolink_bare_uris, Ext_raw_html] })
37+ (unpack inp) (inp, doc $ para ils)
38+
39+autolink :: String -> Inlines
40+autolink = autolinkWith nullAttr
41+
42+autolinkWith :: Attr -> String -> Inlines
43+autolinkWith attr s = linkWith attr s "" (str s)
44+
45+bareLinkTests :: [(Text, Inlines)]
46+bareLinkTests =
47+ [ ("http://google.com is a search engine.",
48+ autolink "http://google.com" <> " is a search engine.")
49+ , ("<a href=\"http://foo.bar.baz\">http://foo.bar.baz</a>",
50+ rawInline "html" "<a href=\"http://foo.bar.baz\">" <>
51+ "http://foo.bar.baz" <> rawInline "html" "</a>")
52+ , ("Try this query: http://google.com?search=fish&time=hour.",
53+ "Try this query: " <> autolink "http://google.com?search=fish&time=hour" <> ".")
54+ , ("HTTPS://GOOGLE.COM,",
55+ autolink "HTTPS://GOOGLE.COM" <> ",")
56+ , ("http://el.wikipedia.org/wiki/Τεχνολογία,",
57+ autolink "http://el.wikipedia.org/wiki/Τεχνολογία" <> ",")
58+ , ("doi:10.1000/182,",
59+ autolink "doi:10.1000/182" <> ",")
60+ , ("git://github.com/foo/bar.git,",
61+ autolink "git://github.com/foo/bar.git" <> ",")
62+ , ("file:///Users/joe/joe.txt, and",
63+ autolink "file:///Users/joe/joe.txt" <> ", and")
64+ , ("mailto:someone@somedomain.com.",
65+ autolink "mailto:someone@somedomain.com" <> ".")
66+ , ("Use http: this is not a link!",
67+ "Use http: this is not a link!")
68+ , ("(http://google.com).",
69+ "(" <> autolink "http://google.com" <> ").")
70+ , ("http://en.wikipedia.org/wiki/Sprite_(computer_graphics)",
71+ autolink "http://en.wikipedia.org/wiki/Sprite_(computer_graphics)")
72+ , ("http://en.wikipedia.org/wiki/Sprite_[computer_graphics]",
73+ link "http://en.wikipedia.org/wiki/Sprite_%5Bcomputer_graphics%5D" ""
74+ (str "http://en.wikipedia.org/wiki/Sprite_[computer_graphics]"))
75+ , ("http://en.wikipedia.org/wiki/Sprite_{computer_graphics}",
76+ link "http://en.wikipedia.org/wiki/Sprite_%7Bcomputer_graphics%7D" ""
77+ (str "http://en.wikipedia.org/wiki/Sprite_{computer_graphics}"))
78+ , ("http://example.com/Notification_Center-GitHub-20101108-140050.jpg",
79+ autolink "http://example.com/Notification_Center-GitHub-20101108-140050.jpg")
80+ , ("https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20",
81+ autolink "https://github.com/github/hubot/blob/master/scripts/cream.js#L20-20")
82+ , ("http://www.rubyonrails.com",
83+ autolink "http://www.rubyonrails.com")
84+ , ("http://www.rubyonrails.com:80",
85+ autolink "http://www.rubyonrails.com:80")
86+ , ("http://www.rubyonrails.com/~minam",
87+ autolink "http://www.rubyonrails.com/~minam")
88+ , ("https://www.rubyonrails.com/~minam",
89+ autolink "https://www.rubyonrails.com/~minam")
90+ , ("http://www.rubyonrails.com/~minam/url%20with%20spaces",
91+ autolink "http://www.rubyonrails.com/~minam/url%20with%20spaces")
92+ , ("http://www.rubyonrails.com/foo.cgi?something=here",
93+ autolink "http://www.rubyonrails.com/foo.cgi?something=here")
94+ , ("http://www.rubyonrails.com/foo.cgi?something=here&and=here",
95+ autolink "http://www.rubyonrails.com/foo.cgi?something=here&and=here")
96+ , ("http://www.rubyonrails.com/contact;new",
97+ autolink "http://www.rubyonrails.com/contact;new")
98+ , ("http://www.rubyonrails.com/contact;new%20with%20spaces",
99+ autolink "http://www.rubyonrails.com/contact;new%20with%20spaces")
100+ , ("http://www.rubyonrails.com/contact;new?with=query&string=params",
101+ autolink "http://www.rubyonrails.com/contact;new?with=query&string=params")
102+ , ("http://www.rubyonrails.com/~minam/contact;new?with=query&string=params",
103+ autolink "http://www.rubyonrails.com/~minam/contact;new?with=query&string=params")
104+ , ("http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007",
105+ autolink "http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007")
106+ , ("http://www.mail-archive.com/rails@lists.rubyonrails.org/",
107+ autolink "http://www.mail-archive.com/rails@lists.rubyonrails.org/")
108+ , ("http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1",
109+ autolink "http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1")
110+ , ("http://en.wikipedia.org/wiki/Texas_hold%27em",
111+ autolink "http://en.wikipedia.org/wiki/Texas_hold%27em")
112+ , ("https://www.google.com/doku.php?id=gps:resource:scs:start",
113+ autolink "https://www.google.com/doku.php?id=gps:resource:scs:start")
114+ , ("http://www.rubyonrails.com",
115+ autolink "http://www.rubyonrails.com")
116+ , ("http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281",
117+ autolink "http://manuals.ruby-on-rails.com/read/chapter.need_a-period/103#page281")
118+ , ("http://foo.example.com/controller/action?parm=value&p2=v2#anchor123",
119+ autolink "http://foo.example.com/controller/action?parm=value&p2=v2#anchor123")
120+ , ("http://foo.example.com:3000/controller/action",
121+ autolink "http://foo.example.com:3000/controller/action")
122+ , ("http://foo.example.com:3000/controller/action+pack",
123+ autolink "http://foo.example.com:3000/controller/action+pack")
124+ , ("http://business.timesonline.co.uk/article/0,,9065-2473189,00.html",
125+ autolink "http://business.timesonline.co.uk/article/0,,9065-2473189,00.html")
126+ , ("http://www.mail-archive.com/ruby-talk@ruby-lang.org/",
127+ autolink "http://www.mail-archive.com/ruby-talk@ruby-lang.org/")
128+ , ("https://example.org/?anchor=lala-",
129+ autolink "https://example.org/?anchor=lala-")
130+ , ("https://example.org/?anchor=-lala",
131+ autolink "https://example.org/?anchor=-lala")
132+ ]
133+
134+{-
135+p_markdown_round_trip :: Block -> Bool
136+p_markdown_round_trip b = matches d' d''
137+ where d' = normalize $ Pandoc (Meta [] [] []) [b]
138+ d'' = normalize
139+ $ readMarkdown def { readerSmart = True }
140+ $ writeMarkdown def d'
141+ matches (Pandoc _ [Plain []]) (Pandoc _ []) = True
142+ matches (Pandoc _ [Para []]) (Pandoc _ []) = True
143+ matches (Pandoc _ [Plain xs]) (Pandoc _ [Para xs']) = xs == xs'
144+ matches x y = x == y
145+-}
146+
147+tests :: [TestTree]
148+tests = [ testGroup "inline code"
149+ [ "with attribute" =:
150+ "`document.write(\"Hello\");`{.javascript}"
151+ =?> para
152+ (codeWith ("",["javascript"],[]) "document.write(\"Hello\");")
153+ , "with attribute space" =:
154+ "`*` {.haskell .special x=\"7\"}"
155+ =?> para (code "*" <> space <> str "{.haskell" <> space <>
156+ str ".special" <> space <> str "x=\"7\"}")
157+ ]
158+ , testGroup "emph and strong"
159+ [ "two strongs in emph" =:
160+ "***a**b **c**d*" =?> para (emph (strong (str "a") <> str "b" <> space
161+ <> strong (str "c") <> str "d"))
162+ , "emph and strong emph alternating" =:
163+ "*xxx* ***xxx*** xxx\n*xxx* ***xxx*** xxx"
164+ =?> para (emph "xxx" <> space <> strong (emph "xxx") <>
165+ space <> "xxx" <> softbreak <>
166+ emph "xxx" <> space <> strong (emph "xxx") <>
167+ space <> "xxx")
168+ , "emph with spaced strong" =:
169+ "*x **xx** x*"
170+ =?> para (emph ("x" <> space <> strong "xx" <> space <> "x"))
171+ , "intraword underscore with opening underscore (#1121)" =:
172+ "_foot_ball_" =?> para (emph (text "foot_ball"))
173+ ]
174+ , testGroup "raw LaTeX"
175+ [ "in URL" =:
176+ "\\begin\n" =?> para (text "\\begin")
177+ ]
178+ , testGroup "raw HTML"
179+ [ "nesting (issue #1330)" =:
180+ "<del>test</del>" =?>
181+ rawBlock "html" "<del>" <> plain (str "test") <>
182+ rawBlock "html" "</del>"
183+ , "invalid tag (issue #1820" =:
184+ "</ div></.div>" =?>
185+ para (text "</ div></.div>")
186+ , "technically invalid comment" =:
187+ "<!-- pandoc --help -->" =?>
188+ rawBlock "html" "<!-- pandoc --help -->"
189+ , test markdownGH "issue 2469" $
190+ "<\n\na>" =?>
191+ para (text "<") <> para (text "a>")
192+ ]
193+ , testGroup "raw email addresses"
194+ [ test markdownGH "issue 2940" $
195+ "**@user**" =?>
196+ para (strong (text "@user"))
197+ ]
198+ , testGroup "emoji"
199+ [ test markdownGH "emoji symbols" $
200+ ":smile: and :+1:" =?> para (text "😄 and 👍")
201+ ]
202+ , "unbalanced brackets" =:
203+ "[[[[[[[[[[[[hi" =?> para (text "[[[[[[[[[[[[hi")
204+ , testGroup "backslash escapes"
205+ [ "in URL" =:
206+ "[hi](/there\\))"
207+ =?> para (link "/there)" "" "hi")
208+ , "in title" =:
209+ "[hi](/there \"a\\\"a\")"
210+ =?> para (link "/there" "a\"a" "hi")
211+ , "in reference link title" =:
212+ "[hi]\n\n[hi]: /there (a\\)a)"
213+ =?> para (link "/there" "a)a" "hi")
214+ , "in reference link URL" =:
215+ "[hi]\n\n[hi]: /there\\.0"
216+ =?> para (link "/there.0" "" "hi")
217+ ]
218+ , testGroup "bare URIs"
219+ (map testBareLink bareLinkTests)
220+ , testGroup "autolinks"
221+ [ "with unicode dash following" =:
222+ "<http://foo.bar>\8212" =?> para (autolink "http://foo.bar" <>
223+ str "\8212")
224+ , "a partial URL (#2277)" =:
225+ "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>" =?>
226+ para (text "<www.boe.es/buscar/act.php?id=BOE-A-1996-8930#a66>")
227+ , "with some attributes" =:
228+ "<http://foo.bar>{#i .j .z k=v}" =?>
229+ para (autolinkWith ("i", ["j", "z"], [("k", "v")]) "http://foo.bar")
230+ , "with some attributes and spaces" =:
231+ "<http://foo.bar> {#i .j .z k=v}" =?>
232+ para (autolink "http://foo.bar" <> space <> text "{#i .j .z k=v}")
233+ ]
234+ , testGroup "links"
235+ [ "no autolink inside link" =:
236+ "[<https://example.org>](url)" =?>
237+ para (link "url" "" (text "<https://example.org>"))
238+ , "no inline link inside link" =:
239+ "[[a](url2)](url)" =?>
240+ para (link "url" "" (text "[a](url2)"))
241+ , "no bare URI inside link" =:
242+ "[https://example.org(](url)" =?>
243+ para (link "url" "" (text "https://example.org("))
244+ ]
245+ , testGroup "Headers"
246+ [ "blank line before header" =:
247+ "\n# Header\n"
248+ =?> headerWith ("header",[],[]) 1 "Header"
249+ , "bracketed text (#2062)" =:
250+ "# [hi]\n"
251+ =?> headerWith ("hi",[],[]) 1 "[hi]"
252+ , "ATX header without trailing #s" =:
253+ "# Foo bar\n\n" =?>
254+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
255+ , "ATX header without trailing #s" =:
256+ "# Foo bar with # #" =?>
257+ headerWith ("foo-bar-with",[],[]) 1 "Foo bar with #"
258+ , "setext header" =:
259+ "Foo bar\n=\n\n Foo bar 2 \n=" =?>
260+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
261+ <> headerWith ("foo-bar-2",[],[]) 1 "Foo bar 2"
262+ ]
263+ , testGroup "Implicit header references"
264+ [ "ATX header without trailing #s" =:
265+ "# Header\n[header]\n\n[header ]\n\n[ header]" =?>
266+ headerWith ("header",[],[]) 1 "Header"
267+ <> para (link "#header" "" (text "header"))
268+ <> para (link "#header" "" (text "header"))
269+ <> para (link "#header" "" (text "header"))
270+ , "ATX header with trailing #s" =:
271+ "# Foo bar #\n[foo bar]\n\n[foo bar ]\n\n[ foo bar]" =?>
272+ headerWith ("foo-bar",[],[]) 1 "Foo bar"
273+ <> para (link "#foo-bar" "" (text "foo bar"))
274+ <> para (link "#foo-bar" "" (text "foo bar"))
275+ <> para (link "#foo-bar" "" (text "foo bar"))
276+ , "setext header" =:
277+ " Header \n=\n\n[header]\n\n[header ]\n\n[ header]" =?>
278+ headerWith ("header",[],[]) 1 "Header"
279+ <> para (link "#header" "" (text "header"))
280+ <> para (link "#header" "" (text "header"))
281+ <> para (link "#header" "" (text "header"))
282+ ]
283+ , testGroup "smart punctuation"
284+ [ test markdownSmart "quote before ellipses"
285+ ("'...hi'"
286+ =?> para (singleQuoted "…hi"))
287+ , test markdownSmart "apostrophe before emph"
288+ ("D'oh! A l'*aide*!"
289+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
290+ , test markdownSmart "apostrophe in French"
291+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
292+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
293+ , test markdownSmart "apostrophe after math" $ -- issue #1909
294+ "The value of the $x$'s and the systems' condition." =?>
295+ para (text "The value of the " <> math "x" <> text "\8217s and the systems\8217 condition.")
296+ ]
297+ , testGroup "footnotes"
298+ [ "indent followed by newline and flush-left text" =:
299+ "[^1]\n\n[^1]: my note\n\n \nnot in note\n"
300+ =?> para (note (para "my note")) <> para "not in note"
301+ , "indent followed by newline and indented text" =:
302+ "[^1]\n\n[^1]: my note\n \n in note\n"
303+ =?> para (note (para "my note" <> para "in note"))
304+ , "recursive note" =:
305+ "[^1]\n\n[^1]: See [^1]\n"
306+ =?> para (note (para "See [^1]"))
307+ ]
308+ , testGroup "lhs"
309+ [ test (purely $ readMarkdown def{ readerExtensions = enableExtension
310+ Ext_literate_haskell pandocExtensions })
311+ "inverse bird tracks and html" $
312+ "> a\n\n< b\n\n<div>\n"
313+ =?> codeBlockWith ("",["sourceCode","literate","haskell"],[]) "a"
314+ <>
315+ codeBlockWith ("",["sourceCode","haskell"],[]) "b"
316+ <>
317+ rawBlock "html" "<div>\n\n"
318+ ]
319+-- the round-trip properties frequently fail
320+-- , testGroup "round trip"
321+-- [ property "p_markdown_round_trip" p_markdown_round_trip
322+-- ]
323+ , testGroup "definition lists"
324+ [ "no blank space" =:
325+ "foo1\n : bar\n\nfoo2\n : bar2\n : bar3\n" =?>
326+ definitionList [ (text "foo1", [plain (text "bar")])
327+ , (text "foo2", [plain (text "bar2"),
328+ plain (text "bar3")])
329+ ]
330+ , "blank space before first def" =:
331+ "foo1\n\n : bar\n\nfoo2\n\n : bar2\n : bar3\n" =?>
332+ definitionList [ (text "foo1", [para (text "bar")])
333+ , (text "foo2", [para (text "bar2"),
334+ plain (text "bar3")])
335+ ]
336+ , "blank space before second def" =:
337+ "foo1\n : bar\n\nfoo2\n : bar2\n\n : bar3\n" =?>
338+ definitionList [ (text "foo1", [plain (text "bar")])
339+ , (text "foo2", [plain (text "bar2"),
340+ para (text "bar3")])
341+ ]
342+ , "laziness" =:
343+ "foo1\n : bar\nbaz\n : bar2\n" =?>
344+ definitionList [ (text "foo1", [plain (text "bar" <>
345+ softbreak <> text "baz"),
346+ plain (text "bar2")])
347+ ]
348+ , "no blank space before first of two paragraphs" =:
349+ "foo1\n : bar\n\n baz\n" =?>
350+ definitionList [ (text "foo1", [para (text "bar") <>
351+ para (text "baz")])
352+ ]
353+ , "first line not indented" =:
354+ "foo\n: bar\n" =?>
355+ definitionList [ (text "foo", [plain (text "bar")]) ]
356+ , "list in definition" =:
357+ "foo\n: - bar\n" =?>
358+ definitionList [ (text "foo", [bulletList [plain (text "bar")]]) ]
359+ , "in div" =:
360+ "<div>foo\n: - bar\n</div>" =?>
361+ divWith nullAttr (definitionList
362+ [ (text "foo", [bulletList [plain (text "bar")]]) ])
363+ ]
364+ , testGroup "+compact_definition_lists"
365+ [ test markdownCDL "basic compact list" $
366+ "foo1\n: bar\n baz\nfoo2\n: bar2\n" =?>
367+ definitionList [ (text "foo1", [plain (text "bar" <> softbreak <>
368+ text "baz")])
369+ , (text "foo2", [plain (text "bar2")])
370+ ]
371+ ]
372+ , testGroup "lists"
373+ [ "issue #1154" =:
374+ " - <div>\n first div breaks\n </div>\n\n <button>if this button exists</button>\n\n <div>\n with this div too.\n </div>\n"
375+ =?> bulletList [divWith nullAttr (para $ text "first div breaks") <>
376+ rawBlock "html" "<button>" <>
377+ plain (text "if this button exists") <>
378+ rawBlock "html" "</button>" <>
379+ divWith nullAttr (para $ text "with this div too.")]
380+ , test markdownGH "issue #1636" $
381+ T.unlines [ "* a"
382+ , "* b"
383+ , "* c"
384+ , " * d" ]
385+ =?>
386+ bulletList [ plain "a"
387+ , plain "b"
388+ , plain "c" <> bulletList [plain "d"] ]
389+ ]
390+ , testGroup "entities"
391+ [ "character references" =:
392+ "&lang; &ouml;" =?> para (text "\10216 ö")
393+ , "numeric" =:
394+ "&#44;&#x44;&#X44;" =?> para (text ",DD")
395+ , "in link title" =:
396+ "[link](/url \"title &lang; &ouml; &#44;\")" =?>
397+ para (link "/url" "title \10216 ö ," (text "link"))
398+ ]
399+ , testGroup "citations"
400+ [ "simple" =:
401+ "@item1" =?> para (cite [
402+ Citation{ citationId = "item1"
403+ , citationPrefix = []
404+ , citationSuffix = []
405+ , citationMode = AuthorInText
406+ , citationNoteNum = 0
407+ , citationHash = 0
408+ }
409+ ] "@item1")
410+ , "key starts with digit" =:
411+ "@1657:huyghens" =?> para (cite [
412+ Citation{ citationId = "1657:huyghens"
413+ , citationPrefix = []
414+ , citationSuffix = []
415+ , citationMode = AuthorInText
416+ , citationNoteNum = 0
417+ , citationHash = 0
418+ }
419+ ] "@1657:huyghens")
420+ ]
421+ , let citation = cite [Citation "cita" [] [] AuthorInText 0 0] (str "@cita")
422+ in testGroup "footnote/link following citation" -- issue #2083
423+ [ "footnote" =:
424+ T.unlines [ "@cita[^note]"
425+ , ""
426+ , "[^note]: note" ] =?>
427+ para (
428+ citation <> note (para $ str "note")
429+ )
430+ , "normal link" =:
431+ "@cita [link](http://www.com)" =?>
432+ para (
433+ citation <> space <> link "http://www.com" "" (str "link")
434+ )
435+ , "reference link" =:
436+ T.unlines [ "@cita [link][link]"
437+ , ""
438+ , "[link]: http://www.com" ] =?>
439+ para (
440+ citation <> space <> link "http://www.com" "" (str "link")
441+ )
442+ , "short reference link" =:
443+ T.unlines [ "@cita [link]"
444+ , ""
445+ , "[link]: http://www.com" ] =?>
446+ para (
447+ citation <> space <> link "http://www.com" "" (str "link")
448+ )
449+ , "implicit header link" =:
450+ T.unlines [ "# Header"
451+ , "@cita [Header]" ] =?>
452+ headerWith ("header",[],[]) 1 (str "Header") <> para (
453+ citation <> space <> link "#header" "" (str "Header")
454+ )
455+ , "regular citation" =:
456+ "@cita [foo]" =?>
457+ para (
458+ cite [Citation "cita" [] [Str "foo"] AuthorInText 0 0]
459+ (str "@cita" <> space <> str "[foo]")
460+ )
461+ ]
462+ ]
test/Tests/Readers/Muse.hs+168−22
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Muse (tests) where
34
5+import Prelude
46import Data.List (intersperse)
57import Data.Text (Text)
68import qualified Data.Text as T
@@ -31,17 +33,17 @@ spcSep = mconcat . intersperse space
3133--
3234makeRoundTrip :: Block -> Block
3335makeRoundTrip Table{} = Para [Str "table was here"]
36+makeRoundTrip (OrderedList (start, LowerAlpha, _) items) = OrderedList (start, Decimal, Period) items
37+makeRoundTrip (OrderedList (start, UpperAlpha, _) items) = OrderedList (start, Decimal, Period) items
3438makeRoundTrip x = x
3539
3640-- Demand that any AST produced by Muse reader and written by Muse writer can be read back exactly the same way.
37−-- Currently we remove tables and compare third rewrite to the second.
38−-- First and second rewrites are not equal yet.
41+-- Currently we remove tables and compare first rewrite to the second.
3942roundTrip :: Block -> Bool
40−roundTrip b = d'' == d'''
43+roundTrip b = d' == d''
4144 where d = walk makeRoundTrip $ Pandoc nullMeta [b]
4245 d' = rewrite d
4346 d'' = rewrite d'
44− d''' = rewrite d''
4547 rewrite = amuse . T.pack . (++ "\n") . T.unpack .
4648 purely (writeMuse def { writerExtensions = extensionsFromList [Ext_amuse]
4749 , writerWrapText = WrapPreserve
@@ -165,14 +167,19 @@ tests =
165167
166168 , "Code tag" =: "<code>foo(bar)</code>" =?> para (code "foo(bar)")
167169
170+ , "Math tag" =: "<math>\\sum_{i=0}^n i^2</math>" =?> para (math "\\sum_{i=0}^n i^2")
171+
168172 , "Verbatim tag" =: "*<verbatim>*</verbatim>*" =?> para (emph "*")
169173
170174 , "Verbatim inside code" =: "<code><verbatim>foo</verbatim></code>" =?> para (code "<verbatim>foo</verbatim>")
171175
172176 , "Verbatim tag after text" =: "Foo <verbatim>bar</verbatim>" =?> para "Foo bar"
173177
178+ , "Class tag" =: "<class name=\"foo\">bar</class>" =?> para (spanWith ("", ["foo"], []) "bar")
179+ , "Class tag without name" =: "<class>foobar</class>" =?> para (spanWith ("", [], []) "foobar")
180+
174181 -- <em> tag should match with the last </em> tag, not verbatim one
175− , "Nested \"</em>\" inside em tag" =: "<em>foo<verbatim></em></verbatim>bar</em>" =?> para (emph ("foo</em>bar"))
182+ , "Nested \"</em>\" inside em tag" =: "<em>foo<verbatim></em></verbatim>bar</em>" =?> para (emph "foo</em>bar")
176183
177184 , testGroup "Links"
178185 [ "Link without description" =:
@@ -181,6 +188,9 @@ tests =
181188 , "Link with description" =:
182189 "[[https://amusewiki.org/][A Muse Wiki]]" =?>
183190 para (link "https://amusewiki.org/" "" (text "A Muse Wiki"))
191+ , "Link with empty description" =:
192+ "[[https://amusewiki.org/][]]" =?>
193+ para (link "https://amusewiki.org/" "" (text ""))
184194 , "Image" =:
185195 "[[image.jpg]]" =?>
186196 para (image "image.jpg" "" mempty)
@@ -199,21 +209,25 @@ tests =
199209 -- This test also makes sure '=' without whitespace is not treated as code markup
200210 , "No implicit links" =: "http://example.org/index.php?action=view&id=1"
201211 =?> para "http://example.org/index.php?action=view&id=1"
212+ , "Link with empty URL" =: "[[][empty URL]]" =?> para (link "" "" (text "empty URL"))
213+ , "No footnotes inside links" =:
214+ "[[https://amusewiki.org/][foo[1]]" =?>
215+ para (link "https://amusewiki.org/" "" (text "foo[1"))
202216 ]
203217
204218 , testGroup "Literal"
205219 [ test emacsMuse "Inline literal"
206220 ("Foo<literal style=\"html\">lit</literal>bar" =?>
207221 para (text "Foo" <> rawInline "html" "lit" <> text "bar"))
208− , "No literal in Text::Amuse" =:
209− "Foo<literal style=\"html\">lit</literal>bar" =?>
210− para "Foo<literal style=\"html\">lit</literal>bar"
222+ , test emacsMuse "Single inline literal in paragraph"
223+ ("<literal style=\"html\">lit</literal>" =?>
224+ para (rawInline "html" "lit"))
211225 ]
212226 ]
213227
214− , testGroup "Blocks"
215− [ testProperty "Round trip" roundTrip,
216− "Block elements end paragraphs" =:
228+ , testGroup "Blocks" $
229+ [ testProperty "Round trip" roundTrip
230+ , "Block elements end paragraphs" =:
217231 T.unlines [ "First paragraph"
218232 , "----"
219233 , "Second paragraph"
@@ -271,6 +285,23 @@ tests =
271285 ] =?>
272286 divWith ("foo", [], []) (para "Foo bar")
273287 ]
288+ , "Biblio" =:
289+ T.unlines [ "<biblio>"
290+ , ""
291+ , "Author, *Title*, description"
292+ , ""
293+ , "Another author, *Another title*, another description"
294+ , ""
295+ , "</biblio>"
296+ ] =?>
297+ divWith ("", ["biblio"], []) (para (text "Author, " <> emph "Title" <> ", description") <>
298+ para (text "Another author, " <> emph "Another title" <> text ", another description"))
299+ , "Play" =:
300+ T.unlines [ "<play>"
301+ , "Foo bar"
302+ , "</play>"
303+ ] =?>
304+ divWith ("", ["play"], []) (para "Foo bar")
274305 , "Verse" =:
275306 T.unlines [ "> This is"
276307 , "> First stanza"
@@ -297,6 +328,7 @@ tests =
297328 ]
298329 ]
299330 , "Verse in list" =: " - > foo" =?> bulletList [ lineBlock [ "foo" ] ]
331+ , "Verse line starting with emphasis" =: "> *foo* bar" =?> lineBlock [ emph "foo" <> text " bar" ]
300332 , "Multiline verse in list" =:
301333 T.unlines [ " - > foo"
302334 , " > bar"
@@ -328,6 +360,12 @@ tests =
328360 , "</quote>"
329361 ] =?>
330362 blockQuote (para "foo" <> blockQuote (para "bar") <> para "baz")
363+ , "Indented quote inside list" =:
364+ T.unlines [ " - <quote>"
365+ , " foo"
366+ , " </quote>"
367+ ] =?>
368+ bulletList [ blockQuote (para "foo") ]
331369 , "Verse tag" =:
332370 T.unlines [ "<verse>"
333371 , ""
@@ -341,6 +379,12 @@ tests =
341379 , text "\160\160One two three"
342380 , ""
343381 ]
382+ , "Verse tag with empty line inside" =:
383+ T.unlines [ "<verse>"
384+ , ""
385+ , "</verse>"
386+ ] =?>
387+ lineBlock [ "" ]
344388 , testGroup "Example"
345389 [ "Braces on separate lines" =:
346390 T.unlines [ "{{{"
@@ -461,12 +505,6 @@ tests =
461505 , "</literal>"
462506 ] =?>
463507 rawBlock "latex" "\\newpage")
464− , "No literal blocks in Text::Amuse" =:
465− T.unlines [ "<literal style=\"latex\">"
466− , "\\newpage"
467− , "</literal>"
468− ] =?>
469− para "<literal style=\"latex\">\n\\newpage\n</literal>"
470508 ]
471509 , "Center" =:
472510 T.unlines [ "<center>"
@@ -487,6 +525,7 @@ tests =
487525 , "Text after empty comment" =: ";\nfoo" =?> para "foo" -- Make sure we don't consume newline while looking for whitespace
488526 , "Not a comment (does not start with a semicolon)" =: " ; Not a comment" =?> para (text "; Not a comment")
489527 , "Not a comment (has no space after semicolon)" =: ";Not a comment" =?> para (text ";Not a comment")
528+ , "Not a comment (semicolon not in the first column)" =: " - ; foo" =?> bulletList [para "; foo"]
490529 ]
491530 , testGroup "Headers"
492531 [ "Part" =:
@@ -518,23 +557,38 @@ tests =
518557 ] =?>
519558 blockQuote (para "* Hi")
520559 , "Headers consume anchors" =:
521− T.unlines [ "** Foo"
560+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
522561 , "#bar"
562+ , "** Foo"
523563 ] =?>
524564 headerWith ("bar",[],[]) 2 "Foo"
525565 , "Headers don't consume anchors separated with a blankline" =:
526− T.unlines [ "** Foo"
527− , ""
566+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
528567 , "#bar"
568+ , ""
569+ , "** Foo"
570+ ] =?>
571+ para (spanWith ("bar", [], []) mempty) <>
572+ header 2 "Foo"
573+ , "Headers terminate paragraph" =:
574+ T.unlines [ "foo"
575+ , "* bar"
529576 ] =?>
530− header 2 "Foo" <>
531− para (spanWith ("bar", [], []) mempty)
577+ para "foo" <> header 1 "bar"
532578 , "Headers terminate lists" =:
533579 T.unlines [ " - foo"
534580 , "* bar"
535581 ] =?>
536582 bulletList [ para "foo" ] <>
537583 header 1 "bar"
584+ , test emacsMuse "Paragraphs terminate Emacs Muse headers"
585+ (T.unlines [ "* Foo"
586+ , "bar"
587+ ] =?> header 1 "Foo" <> para "bar")
588+ , "Paragraphs don't terminate Text::Amuse headers" =:
589+ T.unlines [ "* Foo"
590+ , "bar"
591+ ] =?> header 1 "Foo\nbar"
538592 ]
539593 , testGroup "Directives"
540594 [ "Title" =:
@@ -583,6 +637,11 @@ tests =
583637 , "#anchor and ends here."
584638 ] =?>
585639 para ("Paragraph starts here\n" <> spanWith ("anchor", [], []) mempty <> "and ends here.")
640+ , "Anchor with \"-\"" =:
641+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
642+ , "#anchor-id Target"
643+ ] =?>
644+ para (spanWith ("anchor-id", [], []) mempty <> "Target")
586645 ]
587646 , testGroup "Footnotes"
588647 [ "Simple footnote" =:
@@ -600,6 +659,15 @@ tests =
600659 ] =?>
601660 para (text "Start recursion here" <>
602661 note (para "Recursion continues here[1]"))
662+ , "Nested footnotes" =:
663+ T.unlines [ "Footnote: [1]"
664+ , ""
665+ , "[1] Nested: [2]"
666+ , ""
667+ , "[2] No recursion: [1]"
668+ ] =?>
669+ para (text "Footnote: " <>
670+ note (para (text "Nested: " <> note (para $ text "No recursion: [1]"))))
603671 , "No zero footnotes" =:
604672 T.unlines [ "Here is a footnote[0]."
605673 , ""
@@ -632,6 +700,16 @@ tests =
632700 text " footnotes" <>
633701 note (para "Second footnote")) <>
634702 para (text "Not a note")
703+
704+ -- Verse requires precise indentation, so it is good to test indentation requirements
705+ , "Note continuation with verse" =:
706+ T.unlines [ "Foo[1]"
707+ , ""
708+ , "[1] Bar"
709+ , ""
710+ , " > Baz"
711+ ] =?>
712+ para ("Foo" <> note (para "Bar" <> lineBlock ["Baz"]))
635713 , test emacsMuse "Emacs multiparagraph footnotes"
636714 (T.unlines
637715 [ "First footnote reference[1] and second footnote reference[2]."
@@ -1073,6 +1151,9 @@ tests =
10731151 definitionList [ ("Bar", [ para "baz" ]) ]
10741152 , "One-line definition list" =: " foo :: bar" =?>
10751153 definitionList [ ("foo", [ para "bar" ]) ]
1154+ , "Definition list term may include single colon" =:
1155+ " foo:bar :: baz" =?>
1156+ definitionList [ ("foo:bar", [ para "baz" ]) ]
10761157 , "Definition list term with emphasis" =: " *Foo* :: bar\n" =?>
10771158 definitionList [ (emph "Foo", [ para "bar" ]) ]
10781159 , "Definition list term with :: inside code" =: " foo <code> :: </code> :: bar <code> :: </code> baz\n" =?>
@@ -1086,6 +1167,24 @@ tests =
10861167 definitionList [ ("First term", [ para "Definition of first term\nand its continuation." ])
10871168 , ("Second term", [ para "Definition of second term." ])
10881169 ]
1170+ , "Definition list with verse" =:
1171+ T.unlines
1172+ [ " First term :: Definition of first term"
1173+ , " > First verse"
1174+ , " > Second line of first verse"
1175+ , ""
1176+ , " > Second verse"
1177+ , " > Second line of second verse"
1178+ ] =?>
1179+ definitionList [ ("First term", [ para "Definition of first term" <>
1180+ lineBlock [ text "First verse"
1181+ , text "Second line of first verse"
1182+ ] <>
1183+ lineBlock [ text "Second verse"
1184+ , text "Second line of second verse"
1185+ ]
1186+ ])
1187+ ]
10891188 , test emacsMuse "Multi-line definition lists from Emacs Muse manual"
10901189 (T.unlines
10911190 [ "Term1 ::"
@@ -1191,5 +1290,52 @@ tests =
11911290 , para "Second"
11921291 , para "Third"
11931292 ])
1293+ -- Regression test for a bug caught by round-trip test
1294+ , "Do not consume whitespace while looking for end tag" =:
1295+ T.unlines
1296+ [ "<quote>"
1297+ , " - <quote>"
1298+ , " foo"
1299+ , " </quote>"
1300+ , " bar" -- Do not consume whitespace while looking for arbitrarily indented </quote>
1301+ , "</quote>"
1302+ ] =?>
1303+ blockQuote (bulletList [ blockQuote $ para "foo" ] <> para "bar")
1304+
1305+ , "Unclosed quote tag" =:
1306+ T.unlines
1307+ [ "<quote>"
1308+ , "<verse>"
1309+ , "</quote>"
1310+ , "</verse>"
1311+ ] =?>
1312+ para "<quote>" <> lineBlock [ "</quote>" ]
1313+
1314+ , "Unclosed quote tag inside list" =:
1315+ T.unlines
1316+ [ " - <quote>"
1317+ , " <verse>"
1318+ , " </quote>"
1319+ , " </verse>"
1320+ ] =?>
1321+ bulletList [ para "<quote>" <> lineBlock [ "</quote>" ] ]
1322+
1323+ -- Allowing indented closing tags is dangerous,
1324+ -- as they may terminate lists
1325+ , "No indented closing tags" =:
1326+ T.unlines
1327+ [ "<quote>"
1328+ , ""
1329+ , " - Foo"
1330+ , ""
1331+ , " </quote>"
1332+ , ""
1333+ , " bar"
1334+ , ""
1335+ , " <verse>"
1336+ , " </quote>"
1337+ , " </verse>"
1338+ ] =?>
1339+ para "<quote>" <> bulletList [ para "Foo" <> para "</quote>" <> para "bar" <> lineBlock [ "</quote>" ] ]
11941340 ]
11951341 ]
test/Tests/Readers/Muse.hs.orignew file+1262
@@ -0,0 +1,1262 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Muse (tests) where
3+
4+import Data.List (intersperse)
5+import Data.Text (Text)
6+import qualified Data.Text as T
7+import Test.Tasty
8+import Test.Tasty.QuickCheck
9+import Tests.Helpers
10+import Text.Pandoc
11+import Text.Pandoc.Arbitrary ()
12+import Text.Pandoc.Builder
13+import Text.Pandoc.Shared (underlineSpan)
14+import Text.Pandoc.Walk (walk)
15+
16+amuse :: Text -> Pandoc
17+amuse = purely $ readMuse def { readerExtensions = extensionsFromList [Ext_amuse]}
18+
19+emacsMuse :: Text -> Pandoc
20+emacsMuse = purely $ readMuse def { readerExtensions = emptyExtensions }
21+
22+infix 4 =:
23+(=:) :: ToString c
24+ => String -> (Text, c) -> TestTree
25+(=:) = test amuse
26+
27+spcSep :: [Inlines] -> Inlines
28+spcSep = mconcat . intersperse space
29+
30+-- Tables don't round-trip yet
31+--
32+makeRoundTrip :: Block -> Block
33+makeRoundTrip Table{} = Para [Str "table was here"]
34+makeRoundTrip (OrderedList (start, LowerAlpha, _) items) = OrderedList (start, Decimal, Period) items
35+makeRoundTrip (OrderedList (start, UpperAlpha, _) items) = OrderedList (start, Decimal, Period) items
36+makeRoundTrip x = x
37+
38+-- Demand that any AST produced by Muse reader and written by Muse writer can be read back exactly the same way.
39+-- Currently we remove tables and compare first rewrite to the second.
40+roundTrip :: Block -> Bool
41+roundTrip b = d' == d''
42+ where d = walk makeRoundTrip $ Pandoc nullMeta [b]
43+ d' = rewrite d
44+ d'' = rewrite d'
45+ rewrite = amuse . T.pack . (++ "\n") . T.unpack .
46+ purely (writeMuse def { writerExtensions = extensionsFromList [Ext_amuse]
47+ , writerWrapText = WrapPreserve
48+ })
49+
50+tests :: [TestTree]
51+tests =
52+ [ testGroup "Inlines"
53+ [ "Plain String" =:
54+ "Hello, World" =?>
55+ para "Hello, World"
56+
57+ , "Muse is not XML" =: "&lt;" =?> para "&lt;"
58+
59+ , "Emphasis" =:
60+ "*Foo bar*" =?>
61+ para (emph . spcSep $ ["Foo", "bar"])
62+
63+ , "Comma after closing *" =:
64+ "Foo *bar*, baz" =?>
65+ para ("Foo " <> emph "bar" <> ", baz")
66+
67+ , "Letter after closing *" =:
68+ "Foo *bar*x baz" =?>
69+ para "Foo *bar*x baz"
70+
71+ , "Letter before opening *" =:
72+ "Foo x*bar* baz" =?>
73+ para "Foo x*bar* baz"
74+
75+ , "Emphasis tag" =:
76+ "<em>Foo bar</em>" =?>
77+ para (emph . spcSep $ ["Foo", "bar"])
78+
79+ , "Strong" =:
80+ "**Cider**" =?>
81+ para (strong "Cider")
82+
83+ , "Strong tag" =: "<strong>Strong</strong>" =?> para (strong "Strong")
84+
85+ , "Strong Emphasis" =:
86+ "***strength***" =?>
87+ para (strong . emph $ "strength")
88+
89+ , test emacsMuse "Underline"
90+ ("_Underline_" =?> para (underlineSpan "Underline"))
91+
92+ , "Superscript tag" =: "<sup>Superscript</sup>" =?> para (superscript "Superscript")
93+
94+ , "Subscript tag" =: "<sub>Subscript</sub>" =?> para (subscript "Subscript")
95+
96+ , "Strikeout tag" =: "<del>Strikeout</del>" =?> para (strikeout "Strikeout")
97+
98+ , "Opening inline tags" =: "foo <em> bar <strong>baz" =?> para "foo <em> bar <strong>baz"
99+
100+ , "Closing inline tags" =: "foo </em> bar </strong>baz" =?> para "foo </em> bar </strong>baz"
101+
102+ , "Tag soup" =: "foo <em> bar </strong>baz" =?> para "foo <em> bar </strong>baz"
103+
104+ -- Both inline tags must be within the same paragraph
105+ , "No multiparagraph inline tags" =:
106+ T.unlines [ "First line"
107+ , "<em>Second line"
108+ , ""
109+ , "Fourth line</em>"
110+ ] =?>
111+ para "First line\n<em>Second line" <>
112+ para "Fourth line</em>"
113+
114+ , "Linebreak" =: "Line <br> break" =?> para ("Line" <> linebreak <> "break")
115+
116+ , "Trailing whitespace inside paragraph" =:
117+ T.unlines [ "First line " -- trailing whitespace here
118+ , "second line"
119+ ]
120+ =?> para "First line\nsecond line"
121+
122+ , "Non-breaking space" =: "Foo~~bar" =?> para "Foo\160bar"
123+ , "Single ~" =: "Foo~bar" =?> para "Foo~bar"
124+
125+ , testGroup "Code markup"
126+ [ "Code" =: "=foo(bar)=" =?> para (code "foo(bar)")
127+
128+ , "Not code" =: "a=b= =c=d" =?> para (text "a=b= =c=d")
129+
130+ -- Emacs Muse 3.20 parses this as code, we follow Amusewiki
131+ , "Not code if closing = is detached" =: "=this is not a code =" =?> para "=this is not a code ="
132+
133+ , "Not code if opening = is detached" =: "= this is not a code=" =?> para "= this is not a code="
134+
135+ , "Code if followed by comma" =:
136+ "Foo =bar=, baz" =?>
137+ para (text "Foo " <> code "bar" <> text ", baz")
138+
139+ , "One character code" =: "=c=" =?> para (code "c")
140+
141+ , "Three = characters is not a code" =: "===" =?> para "==="
142+
143+ , "Multiline code markup" =:
144+ "foo =bar\nbaz= end of code" =?>
145+ para (text "foo " <> code "bar\nbaz" <> text " end of code")
146+
147+{- Emacs Muse 3.20 has a bug: it publishes
148+ - <p>foo <code>bar
149+ -
150+ - baz</code> foo</p>
151+ - which is displayed as one paragraph by browsers.
152+ - We follow Amusewiki here and avoid joining paragraphs.
153+ -}
154+ , "No multiparagraph code" =:
155+ T.unlines [ "foo =bar"
156+ , ""
157+ , "baz= foo"
158+ ] =?>
159+ para "foo =bar" <>
160+ para "baz= foo"
161+
162+ , "Code at the beginning of paragraph but not first column" =:
163+ " - =foo=" =?> bulletList [ para $ code "foo" ]
164+ ]
165+
166+ , "Code tag" =: "<code>foo(bar)</code>" =?> para (code "foo(bar)")
167+
168+ , "Verbatim tag" =: "*<verbatim>*</verbatim>*" =?> para (emph "*")
169+
170+ , "Verbatim inside code" =: "<code><verbatim>foo</verbatim></code>" =?> para (code "<verbatim>foo</verbatim>")
171+
172+ , "Verbatim tag after text" =: "Foo <verbatim>bar</verbatim>" =?> para "Foo bar"
173+
174+ , "Class tag" =: "<class name=\"foo\">bar</class>" =?> para (spanWith ("", ["foo"], []) "bar")
175+ , "Class tag without name" =: "<class>foobar</class>" =?> para (spanWith ("", [], []) "foobar")
176+
177+ -- <em> tag should match with the last </em> tag, not verbatim one
178+ , "Nested \"</em>\" inside em tag" =: "<em>foo<verbatim></em></verbatim>bar</em>" =?> para (emph "foo</em>bar")
179+
180+ , testGroup "Links"
181+ [ "Link without description" =:
182+ "[[https://amusewiki.org/]]" =?>
183+ para (link "https://amusewiki.org/" "" (str "https://amusewiki.org/"))
184+ , "Link with description" =:
185+ "[[https://amusewiki.org/][A Muse Wiki]]" =?>
186+ para (link "https://amusewiki.org/" "" (text "A Muse Wiki"))
187+ , "Image" =:
188+ "[[image.jpg]]" =?>
189+ para (image "image.jpg" "" mempty)
190+ , "Image with description" =:
191+ "[[image.jpg][Image]]" =?>
192+ para (image "image.jpg" "" (text "Image"))
193+ , "Image link" =:
194+ "[[URL:image.jpg]]" =?>
195+ para (link "image.jpg" "" (str "image.jpg"))
196+ , "Image link with description" =:
197+ "[[URL:image.jpg][Image]]" =?>
198+ para (link "image.jpg" "" (text "Image"))
199+ -- Implicit links are supported in Emacs Muse, but not in Amusewiki:
200+ -- https://github.com/melmothx/text-amuse/issues/18
201+ --
202+ -- This test also makes sure '=' without whitespace is not treated as code markup
203+ , "No implicit links" =: "http://example.org/index.php?action=view&id=1"
204+ =?> para "http://example.org/index.php?action=view&id=1"
205+ ]
206+
207+ , testGroup "Literal"
208+ [ test emacsMuse "Inline literal"
209+ ("Foo<literal style=\"html\">lit</literal>bar" =?>
210+ para (text "Foo" <> rawInline "html" "lit" <> text "bar"))
211+ ]
212+ ]
213+
214+ , testGroup "Blocks"
215+ [ testProperty "Round trip" roundTrip,
216+ "Block elements end paragraphs" =:
217+ T.unlines [ "First paragraph"
218+ , "----"
219+ , "Second paragraph"
220+ ] =?> para (text "First paragraph") <> horizontalRule <> para (text "Second paragraph")
221+ , testGroup "Horizontal rule"
222+ [ "Less than 4 dashes is not a horizontal rule" =: "---" =?> para (text "---")
223+ , "4 dashes is a horizontal rule" =: "----" =?> horizontalRule
224+ , "5 dashes is a horizontal rule" =: "-----" =?> horizontalRule
225+ , "4 dashes with spaces is a horizontal rule" =: "---- " =?> horizontalRule
226+ ]
227+ , testGroup "Paragraphs"
228+ [ "Simple paragraph" =:
229+ T.unlines [ "First line"
230+ , "second line."
231+ ] =?>
232+ para "First line\nsecond line."
233+ , "Indented paragraph" =:
234+ T.unlines [ " First line"
235+ , "second line."
236+ ] =?>
237+ para "First line\nsecond line."
238+ -- Emacs Muse starts a blockquote on the second line.
239+ -- We copy Amusewiki behavior and require a blank line to start a blockquote.
240+ , "Indentation in the middle of paragraph" =:
241+ T.unlines [ "First line"
242+ , " second line"
243+ , "third line"
244+ ] =?>
245+ para "First line\nsecond line\nthird line"
246+ , "Quote" =:
247+ " This is a quotation\n" =?>
248+ blockQuote (para "This is a quotation")
249+ , "Indentation does not indicate quote inside quote tag" =:
250+ T.unlines [ "<quote>"
251+ , " Not a nested quote"
252+ , "</quote>"
253+ ] =?>
254+ blockQuote (para "Not a nested quote")
255+ , "Multiline quote" =:
256+ T.unlines [ " This is a quotation"
257+ , " with a continuation"
258+ ] =?>
259+ blockQuote (para "This is a quotation\nwith a continuation")
260+ , testGroup "Div"
261+ [ "Div without id" =:
262+ T.unlines [ "<div>"
263+ , "Foo bar"
264+ , "</div>"
265+ ] =?>
266+ divWith nullAttr (para "Foo bar")
267+ , "Div with id" =:
268+ T.unlines [ "<div id=\"foo\">"
269+ , "Foo bar"
270+ , "</div>"
271+ ] =?>
272+ divWith ("foo", [], []) (para "Foo bar")
273+ ]
274+ , "Verse" =:
275+ T.unlines [ "> This is"
276+ , "> First stanza"
277+ , ">" -- Emacs produces verbatim ">" here, we follow Amusewiki
278+ , "> And this is"
279+ , "> Second stanza"
280+ , ">"
281+ , ""
282+ , ">"
283+ , ""
284+ , "> Another verse"
285+ , "> is here"
286+ ] =?>
287+ lineBlock [ "This is"
288+ , "First stanza"
289+ , ""
290+ , "And this is"
291+ , "\160\160Second stanza"
292+ , ""
293+ ] <>
294+ lineBlock [ "" ] <>
295+ lineBlock [ "Another verse"
296+ , "\160\160\160is here"
297+ ]
298+ ]
299+ , "Verse in list" =: " - > foo" =?> bulletList [ lineBlock [ "foo" ] ]
300+ , "Verse line starting with emphasis" =: "> *foo* bar" =?> lineBlock [ emph "foo" <> text " bar" ]
301+ , "Multiline verse in list" =:
302+ T.unlines [ " - > foo"
303+ , " > bar"
304+ ] =?>
305+ bulletList [ lineBlock [ "foo", "bar" ] ]
306+ , "Paragraph after verse in list" =:
307+ T.unlines [ " - > foo"
308+ , " bar"
309+ ] =?>
310+ bulletList [ lineBlock [ "foo" ] <> para "bar" ]
311+ , "Empty quote tag" =:
312+ T.unlines [ "<quote>"
313+ , "</quote>"
314+ ]
315+ =?> blockQuote mempty
316+ , "Quote tag" =:
317+ T.unlines [ "<quote>"
318+ , "Hello, world"
319+ , "</quote>"
320+ ]
321+ =?> blockQuote (para $ text "Hello, world")
322+ , "Nested quote tag" =:
323+ T.unlines [ "<quote>"
324+ , "foo"
325+ , "<quote>"
326+ , "bar"
327+ , "</quote>"
328+ , "baz"
329+ , "</quote>"
330+ ] =?>
331+ blockQuote (para "foo" <> blockQuote (para "bar") <> para "baz")
332+ , "Indented quote inside list" =:
333+ T.unlines [ " - <quote>"
334+ , " foo"
335+ , " </quote>"
336+ ] =?>
337+ bulletList [ blockQuote (para "foo") ]
338+ , "Verse tag" =:
339+ T.unlines [ "<verse>"
340+ , ""
341+ , "Foo bar baz"
342+ , " One two three"
343+ , ""
344+ , "</verse>"
345+ ] =?>
346+ lineBlock [ ""
347+ , text "Foo bar baz"
348+ , text "\160\160One two three"
349+ , ""
350+ ]
351+ , "Verse tag with empty line inside" =:
352+ T.unlines [ "<verse>"
353+ , ""
354+ , "</verse>"
355+ ] =?>
356+ lineBlock [ "" ]
357+ , testGroup "Example"
358+ [ "Braces on separate lines" =:
359+ T.unlines [ "{{{"
360+ , "Example line"
361+ , "}}}"
362+ ] =?>
363+ codeBlock "Example line"
364+ , "Spaces after opening braces" =:
365+ T.unlines [ "{{{ "
366+ , "Example line"
367+ , "}}}"
368+ ] =?>
369+ codeBlock "Example line"
370+ , "One blank line in the beginning" =:
371+ T.unlines [ "{{{"
372+ , ""
373+ , "Example line"
374+ , "}}}"
375+ ] =?>
376+ codeBlock "\nExample line"
377+ , "One blank line in the end" =:
378+ T.unlines [ "{{{"
379+ , "Example line"
380+ , ""
381+ , "}}}"
382+ ] =?>
383+ codeBlock "Example line\n"
384+ -- Amusewiki requires braces to be on separate line,
385+ -- this is an extension.
386+ , "One line" =:
387+ "{{{Example line}}}" =?>
388+ codeBlock "Example line"
389+ ]
390+ , testGroup "Example tag"
391+ [ "Tags on separate lines" =:
392+ T.unlines [ "<example>"
393+ , "Example line"
394+ , "</example>"
395+ ] =?>
396+ codeBlock "Example line"
397+ , "One line" =:
398+ "<example>Example line</example>" =?>
399+ codeBlock "Example line"
400+ , "One blank line in the beginning" =:
401+ T.unlines [ "<example>"
402+ , ""
403+ , "Example line"
404+ , "</example>"
405+ ] =?>
406+ codeBlock "\nExample line"
407+ , "One blank line in the end" =:
408+ T.unlines [ "<example>"
409+ , "Example line"
410+ , ""
411+ , "</example>"
412+ ] =?>
413+ codeBlock "Example line\n"
414+ , "Example inside list" =:
415+ T.unlines [ " - <example>"
416+ , " foo"
417+ , " </example>"
418+ ] =?>
419+ bulletList [ codeBlock "foo" ]
420+ , "Empty example inside list" =:
421+ T.unlines [ " - <example>"
422+ , " </example>"
423+ ] =?>
424+ bulletList [ codeBlock "" ]
425+ , "Example inside list with empty lines" =:
426+ T.unlines [ " - <example>"
427+ , " foo"
428+ , " </example>"
429+ , ""
430+ , " bar"
431+ , ""
432+ , " <example>"
433+ , " baz"
434+ , " </example>"
435+ ] =?>
436+ bulletList [ codeBlock "foo" <> para "bar" <> codeBlock "baz" ]
437+ , "Indented example inside list" =:
438+ T.unlines [ " - <example>"
439+ , " foo"
440+ , " </example>"
441+ ] =?>
442+ bulletList [ codeBlock "foo" ]
443+ , "Example inside definition list" =:
444+ T.unlines [ " foo :: <example>"
445+ , " bar"
446+ , " </example>"
447+ ] =?>
448+ definitionList [ ("foo", [codeBlock "bar"]) ]
449+ , "Example inside list definition with empty lines" =:
450+ T.unlines [ " term :: <example>"
451+ , " foo"
452+ , " </example>"
453+ , ""
454+ , " bar"
455+ , ""
456+ , " <example>"
457+ , " baz"
458+ , " </example>"
459+ ] =?>
460+ definitionList [ ("term", [codeBlock "foo" <> para "bar" <> codeBlock "baz"]) ]
461+ , "Example inside note" =:
462+ T.unlines [ "Foo[1]"
463+ , ""
464+ , "[1] <example>"
465+ , " bar"
466+ , " </example>"
467+ ] =?>
468+ para ("Foo" <> note (codeBlock "bar"))
469+ ]
470+ , testGroup "Literal blocks"
471+ [ test emacsMuse "Literal block"
472+ (T.unlines [ "<literal style=\"latex\">"
473+ , "\\newpage"
474+ , "</literal>"
475+ ] =?>
476+ rawBlock "latex" "\\newpage")
477+ ]
478+ , "Center" =:
479+ T.unlines [ "<center>"
480+ , "Hello, world"
481+ , "</center>"
482+ ] =?>
483+ para (text "Hello, world")
484+ , "Right" =:
485+ T.unlines [ "<right>"
486+ , "Hello, world"
487+ , "</right>"
488+ ] =?>
489+ para (text "Hello, world")
490+ , testGroup "Comments"
491+ [ "Comment tag" =: "<comment>\nThis is a comment\n</comment>" =?> (mempty::Blocks)
492+ , "Line comment" =: "; Comment" =?> (mempty::Blocks)
493+ , "Empty comment" =: ";" =?> (mempty::Blocks)
494+ , "Text after empty comment" =: ";\nfoo" =?> para "foo" -- Make sure we don't consume newline while looking for whitespace
495+ , "Not a comment (does not start with a semicolon)" =: " ; Not a comment" =?> para (text "; Not a comment")
496+ , "Not a comment (has no space after semicolon)" =: ";Not a comment" =?> para (text ";Not a comment")
497+ ]
498+ , testGroup "Headers"
499+ [ "Part" =:
500+ "* First level" =?>
501+ header 1 "First level"
502+ , "Chapter" =:
503+ "** Second level" =?>
504+ header 2 "Second level"
505+ , "Section" =:
506+ "*** Third level" =?>
507+ header 3 "Third level"
508+ , "Subsection" =:
509+ "**** Fourth level" =?>
510+ header 4 "Fourth level"
511+ , "Subsubsection" =:
512+ "***** Fifth level" =?>
513+ header 5 "Fifth level"
514+ , "Whitespace is required after *" =: "**Not a header" =?> para "**Not a header"
515+ , "No headers in footnotes" =:
516+ T.unlines [ "Foo[1]"
517+ , "[1] * Bar"
518+ ] =?>
519+ para (text "Foo" <>
520+ note (para "* Bar"))
521+ , "No headers in quotes" =:
522+ T.unlines [ "<quote>"
523+ , "* Hi"
524+ , "</quote>"
525+ ] =?>
526+ blockQuote (para "* Hi")
527+ , "Headers consume anchors" =:
528+ T.unlines [ "** Foo"
529+ , "#bar"
530+ ] =?>
531+ headerWith ("bar",[],[]) 2 "Foo"
532+ , "Headers don't consume anchors separated with a blankline" =:
533+ T.unlines [ "** Foo"
534+ , ""
535+ , "#bar"
536+ ] =?>
537+ header 2 "Foo" <>
538+ para (spanWith ("bar", [], []) mempty)
539+ , "Headers terminate lists" =:
540+ T.unlines [ " - foo"
541+ , "* bar"
542+ ] =?>
543+ bulletList [ para "foo" ] <>
544+ header 1 "bar"
545+ ]
546+ , testGroup "Directives"
547+ [ "Title" =:
548+ "#title Document title" =?>
549+ let titleInline = toList "Document title"
550+ meta = setMeta "title" (MetaInlines titleInline) nullMeta
551+ in Pandoc meta mempty
552+ -- Emacs Muse documentation says that "You can use any combination
553+ -- of uppercase and lowercase letters for directives",
554+ -- but also allows '-', which is not documented, but used for disable-tables.
555+ , test emacsMuse "Disable tables"
556+ ("#disable-tables t" =?>
557+ Pandoc (setMeta "disable-tables" (MetaInlines $ toList "t") nullMeta) mempty)
558+ , "Multiple directives" =:
559+ T.unlines [ "#title Document title"
560+ , "#subtitle Document subtitle"
561+ ] =?>
562+ Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $
563+ setMeta "subtitle" (MetaInlines $ toList "Document subtitle") nullMeta) mempty
564+ , "Multiline directive" =:
565+ T.unlines [ "#title Document title"
566+ , "#notes First line"
567+ , "and second line"
568+ , "#author Name"
569+ ] =?>
570+ Pandoc (setMeta "title" (MetaInlines $ toList "Document title") $
571+ setMeta "notes" (MetaInlines $ toList "First line\nand second line") $
572+ setMeta "author" (MetaInlines $ toList "Name") nullMeta) mempty
573+ ]
574+ , testGroup "Anchors"
575+ [ "Anchor" =:
576+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
577+ , "#anchor Target"
578+ ] =?>
579+ para (spanWith ("anchor", [], []) mempty <> "Target")
580+ , "Anchor cannot start with a number" =:
581+ T.unlines [ "; A comment to make sure anchor is not parsed as a directive"
582+ , "#0notanchor Target"
583+ ] =?>
584+ para "#0notanchor Target"
585+ , "Not anchor if starts with a space" =:
586+ " #notanchor Target" =?>
587+ para "#notanchor Target"
588+ , "Anchor inside a paragraph" =:
589+ T.unlines [ "Paragraph starts here"
590+ , "#anchor and ends here."
591+ ] =?>
592+ para ("Paragraph starts here\n" <> spanWith ("anchor", [], []) mempty <> "and ends here.")
593+ ]
594+ , testGroup "Footnotes"
595+ [ "Simple footnote" =:
596+ T.unlines [ "Here is a footnote[1]."
597+ , ""
598+ , "[1] Footnote contents"
599+ ] =?>
600+ para (text "Here is a footnote" <>
601+ note (para "Footnote contents") <>
602+ str ".")
603+ , "Recursive footnote" =:
604+ T.unlines [ "Start recursion here[1]"
605+ , ""
606+ , "[1] Recursion continues here[1]"
607+ ] =?>
608+ para (text "Start recursion here" <>
609+ note (para "Recursion continues here[1]"))
610+ , "No zero footnotes" =:
611+ T.unlines [ "Here is a footnote[0]."
612+ , ""
613+ , "[0] Footnote contents"
614+ ] =?>
615+ para "Here is a footnote[0]." <>
616+ para "[0] Footnote contents"
617+ , "Footnotes can't start with zero" =:
618+ T.unlines [ "Here is a footnote[01]."
619+ , ""
620+ , "[01] Footnote contents"
621+ ] =?>
622+ para "Here is a footnote[01]." <>
623+ para "[01] Footnote contents"
624+ , testGroup "Multiparagraph footnotes"
625+ [ "Amusewiki multiparagraph footnotes" =:
626+ T.unlines [ "Multiparagraph[1] footnotes[2]"
627+ , ""
628+ , "[1] First footnote paragraph"
629+ , ""
630+ , " Second footnote paragraph"
631+ , "with continuation"
632+ , ""
633+ , "Not a note"
634+ , "[2] Second footnote"
635+ ] =?>
636+ para (text "Multiparagraph" <>
637+ note (para "First footnote paragraph" <>
638+ para "Second footnote paragraph\nwith continuation") <>
639+ text " footnotes" <>
640+ note (para "Second footnote")) <>
641+ para (text "Not a note")
642+
643+ -- Verse requires precise indentation, so it is good to test indentation requirements
644+ , "Note continuation with verse" =:
645+ T.unlines [ "Foo[1]"
646+ , ""
647+ , "[1] Bar"
648+ , ""
649+ , " > Baz"
650+ ] =?>
651+ para ("Foo" <> note (para "Bar" <> lineBlock ["Baz"]))
652+ , test emacsMuse "Emacs multiparagraph footnotes"
653+ (T.unlines
654+ [ "First footnote reference[1] and second footnote reference[2]."
655+ , ""
656+ , "[1] First footnote paragraph"
657+ , ""
658+ , "Second footnote"
659+ , "paragraph"
660+ , ""
661+ , "[2] Third footnote paragraph"
662+ , ""
663+ , "Fourth footnote paragraph"
664+ ] =?>
665+ para (text "First footnote reference" <>
666+ note (para "First footnote paragraph" <>
667+ para "Second footnote\nparagraph") <>
668+ text " and second footnote reference" <>
669+ note (para "Third footnote paragraph" <>
670+ para "Fourth footnote paragraph") <>
671+ text "."))
672+ ]
673+ ]
674+ ]
675+ , testGroup "Tables"
676+ [ "Two cell table" =:
677+ "One | Two" =?>
678+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
679+ []
680+ [[plain "One", plain "Two"]]
681+ , "Table with multiple words" =:
682+ "One two | three four" =?>
683+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
684+ []
685+ [[plain "One two", plain "three four"]]
686+ , "Not a table" =:
687+ "One| Two" =?>
688+ para (text "One| Two")
689+ , "Not a table again" =:
690+ "One |Two" =?>
691+ para (text "One |Two")
692+ , "Two line table" =:
693+ T.unlines
694+ [ "One | Two"
695+ , "Three | Four"
696+ ] =?>
697+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
698+ []
699+ [[plain "One", plain "Two"],
700+ [plain "Three", plain "Four"]]
701+ , "Table with one header" =:
702+ T.unlines
703+ [ "First || Second"
704+ , "Third | Fourth"
705+ ] =?>
706+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
707+ [plain "First", plain "Second"]
708+ [[plain "Third", plain "Fourth"]]
709+ , "Table with two headers" =:
710+ T.unlines
711+ [ "First || header"
712+ , "Second || header"
713+ , "Foo | bar"
714+ ] =?>
715+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
716+ [plain "First", plain "header"]
717+ [[plain "Second", plain "header"],
718+ [plain "Foo", plain "bar"]]
719+ , "Header and footer reordering" =:
720+ T.unlines
721+ [ "Foo ||| bar"
722+ , "Baz || foo"
723+ , "Bar | baz"
724+ ] =?>
725+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
726+ [plain "Baz", plain "foo"]
727+ [[plain "Bar", plain "baz"],
728+ [plain "Foo", plain "bar"]]
729+ , "Table with caption" =:
730+ T.unlines
731+ [ "Foo || bar || baz"
732+ , "First | row | here"
733+ , "Second | row | there"
734+ , "|+ Table caption +|"
735+ ] =?>
736+ table (text "Table caption") (replicate 3 (AlignDefault, 0.0))
737+ [plain "Foo", plain "bar", plain "baz"]
738+ [[plain "First", plain "row", plain "here"],
739+ [plain "Second", plain "row", plain "there"]]
740+ , "Caption without table" =:
741+ "|+ Foo bar baz +|" =?>
742+ table (text "Foo bar baz") [] [] []
743+ , "Table indented with space" =:
744+ T.unlines
745+ [ " Foo | bar"
746+ , " Baz | foo"
747+ , " Bar | baz"
748+ ] =?>
749+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
750+ []
751+ [[plain "Foo", plain "bar"],
752+ [plain "Baz", plain "foo"],
753+ [plain "Bar", plain "baz"]]
754+ , "Empty cells" =:
755+ T.unlines
756+ [ " | Foo"
757+ , " |"
758+ , " bar |"
759+ , " || baz"
760+ ] =?>
761+ table mempty [(AlignDefault, 0.0), (AlignDefault, 0.0)]
762+ [plain "", plain "baz"]
763+ [[plain "", plain "Foo"],
764+ [plain "", plain ""],
765+ [plain "bar", plain ""]]
766+ ]
767+ , testGroup "Lists"
768+ [ "Bullet list" =:
769+ T.unlines
770+ [ " - Item1"
771+ , ""
772+ , " - Item2"
773+ ] =?>
774+ bulletList [ para "Item1"
775+ , para "Item2"
776+ ]
777+ , "Ordered list" =:
778+ T.unlines
779+ [ " 1. Item1"
780+ , ""
781+ , " 2. Item2"
782+ ] =?>
783+ orderedListWith (1, Decimal, Period) [ para "Item1"
784+ , para "Item2"
785+ ]
786+ , "Ordered list with implicit numbers" =:
787+ T.unlines
788+ [ " 1. Item1"
789+ , ""
790+ , " 1. Item2"
791+ , ""
792+ , " 1. Item3"
793+ ] =?>
794+ orderedListWith (1, Decimal, Period) [ para "Item1"
795+ , para "Item2"
796+ , para "Item3"
797+ ]
798+ , "Ordered list with roman numerals" =:
799+ T.unlines
800+ [ " i. First"
801+ , " ii. Second"
802+ , " iii. Third"
803+ , " iv. Fourth"
804+ ] =?>
805+ orderedListWith (1, LowerRoman, Period) [ para "First"
806+ , para "Second"
807+ , para "Third"
808+ , para "Fourth"
809+ ]
810+ , "Bullet list with empty items" =:
811+ T.unlines
812+ [ " -"
813+ , ""
814+ , " - Item2"
815+ ] =?>
816+ bulletList [ mempty
817+ , para "Item2"
818+ ]
819+ , "Ordered list with empty items" =:
820+ T.unlines
821+ [ " 1."
822+ , ""
823+ , " 2."
824+ , ""
825+ , " 3. Item3"
826+ ] =?>
827+ orderedListWith (1, Decimal, Period) [ mempty
828+ , mempty
829+ , para "Item3"
830+ ]
831+ , "Bullet list with last item empty" =:
832+ T.unlines
833+ [ " -"
834+ , ""
835+ , "foo"
836+ ] =?>
837+ bulletList [ mempty ] <>
838+ para "foo"
839+ , testGroup "Nested lists"
840+ [ "Nested bullet list" =:
841+ T.unlines [ " - Item1"
842+ , " - Item2"
843+ , " - Item3"
844+ , " - Item4"
845+ , " - Item5"
846+ , " - Item6"
847+ ] =?>
848+ bulletList [ para "Item1" <>
849+ bulletList [ para "Item2" <>
850+ bulletList [ para "Item3" ]
851+ , para "Item4" <>
852+ bulletList [ para "Item5" ]
853+ ]
854+ , para "Item6"
855+ ]
856+ , "Nested ordered list" =:
857+ T.unlines [ " 1. Item1"
858+ , " 1. Item2"
859+ , " 1. Item3"
860+ , " 2. Item4"
861+ , " 1. Item5"
862+ , " 2. Item6"
863+ ] =?>
864+ orderedListWith (1, Decimal, Period) [ para "Item1" <>
865+ orderedListWith (1, Decimal, Period) [ para "Item2" <>
866+ orderedListWith (1, Decimal, Period) [ para "Item3" ]
867+ , para "Item4" <>
868+ orderedListWith (1, Decimal, Period) [ para "Item5" ]
869+ ]
870+ , para "Item6"
871+ ]
872+ , "Mixed nested list" =:
873+ T.unlines
874+ [ " - Item1"
875+ , " - Item2"
876+ , " - Item3"
877+ , " - Item4"
878+ , " 1. Nested"
879+ , " 2. Ordered"
880+ , " 3. List"
881+ ] =?>
882+ bulletList [ mconcat [ para "Item1"
883+ , bulletList [ para "Item2"
884+ , para "Item3"
885+ ]
886+ ]
887+ , mconcat [ para "Item4"
888+ , orderedListWith (1, Decimal, Period) [ para "Nested"
889+ , para "Ordered"
890+ , para "List"
891+ ]
892+ ]
893+ ]
894+ , "Text::Amuse includes only one space in list marker" =:
895+ T.unlines
896+ [ " - First item"
897+ , " - Nested item"
898+ ] =?>
899+ bulletList [ para "First item" <> bulletList [ para "Nested item"]]
900+ ]
901+ , "List continuation" =:
902+ T.unlines
903+ [ " - a"
904+ , ""
905+ , " b"
906+ , ""
907+ , " c"
908+ ] =?>
909+ bulletList [ mconcat [ para "a"
910+ , para "b"
911+ , para "c"
912+ ]
913+ ]
914+ , "List continuation afeter nested list" =:
915+ T.unlines
916+ [ " - - foo"
917+ , ""
918+ , " bar"
919+ ] =?>
920+ bulletList [ bulletList [ para "foo" ] <>
921+ para "bar"
922+ ]
923+ -- Emacs Muse allows to separate lists with two or more blank lines.
924+ -- Text::Amuse (Amusewiki engine) always creates a single list as of version 0.82.
925+ -- pandoc follows Emacs Muse behavior
926+ , testGroup "Blank lines"
927+ [ "Blank lines between list items are not required" =:
928+ T.unlines
929+ [ " - Foo"
930+ , " - Bar"
931+ ] =?>
932+ bulletList [ para "Foo"
933+ , para "Bar"
934+ ]
935+ , "One blank line between list items is allowed" =:
936+ T.unlines
937+ [ " - Foo"
938+ , ""
939+ , " - Bar"
940+ ] =?>
941+ bulletList [ para "Foo"
942+ , para "Bar"
943+ ]
944+ , "Two blank lines separate lists" =:
945+ T.unlines
946+ [ " - Foo"
947+ , ""
948+ , ""
949+ , " - Bar"
950+ ] =?>
951+ bulletList [ para "Foo" ] <> bulletList [ para "Bar" ]
952+ , "No blank line after multiline first item" =:
953+ T.unlines
954+ [ " - Foo"
955+ , " bar"
956+ , " - Baz"
957+ ] =?>
958+ bulletList [ para "Foo\nbar"
959+ , para "Baz"
960+ ]
961+ , "One blank line after multiline first item" =:
962+ T.unlines
963+ [ " - Foo"
964+ , " bar"
965+ , ""
966+ , " - Baz"
967+ ] =?>
968+ bulletList [ para "Foo\nbar"
969+ , para "Baz"
970+ ]
971+ , "Two blank lines after multiline first item" =:
972+ T.unlines
973+ [ " - Foo"
974+ , " bar"
975+ , ""
976+ , ""
977+ , " - Baz"
978+ ] =?>
979+ bulletList [ para "Foo\nbar" ] <> bulletList [ para "Baz" ]
980+ , "No blank line after list continuation" =:
981+ T.unlines
982+ [ " - Foo"
983+ , ""
984+ , " bar"
985+ , " - Baz"
986+ ] =?>
987+ bulletList [ para "Foo" <> para "bar"
988+ , para "Baz"
989+ ]
990+ , "One blank line after list continuation" =:
991+ T.unlines
992+ [ " - Foo"
993+ , ""
994+ , " bar"
995+ , ""
996+ , " - Baz"
997+ ] =?>
998+ bulletList [ para "Foo" <> para "bar"
999+ , para "Baz"
1000+ ]
1001+ , "Two blank lines after list continuation" =:
1002+ T.unlines
1003+ [ " - Foo"
1004+ , ""
1005+ , " bar"
1006+ , ""
1007+ , ""
1008+ , " - Baz"
1009+ ] =?>
1010+ bulletList [ para "Foo" <> para "bar" ] <> bulletList [ para "Baz" ]
1011+ , "No blank line after blockquote" =:
1012+ T.unlines
1013+ [ " - <quote>"
1014+ , " foo"
1015+ , " </quote>"
1016+ , " - bar"
1017+ ] =?>
1018+ bulletList [ blockQuote $ para "foo", para "bar" ]
1019+ , "One blank line after blockquote" =:
1020+ T.unlines
1021+ [ " - <quote>"
1022+ , " foo"
1023+ , " </quote>"
1024+ , ""
1025+ , " - bar"
1026+ ] =?>
1027+ bulletList [ blockQuote $ para "foo", para "bar" ]
1028+ , "Two blank lines after blockquote" =:
1029+ T.unlines
1030+ [ " - <quote>"
1031+ , " foo"
1032+ , " </quote>"
1033+ , ""
1034+ , ""
1035+ , " - bar"
1036+ ] =?>
1037+ bulletList [ blockQuote $ para "foo" ] <> bulletList [ para "bar" ]
1038+ , "No blank line after verse" =:
1039+ T.unlines
1040+ [ " - > foo"
1041+ , " - bar"
1042+ ] =?>
1043+ bulletList [ lineBlock [ "foo" ], para "bar" ]
1044+ , "One blank line after verse" =:
1045+ T.unlines
1046+ [ " - > foo"
1047+ , ""
1048+ , " - bar"
1049+ ] =?>
1050+ bulletList [ lineBlock [ "foo" ], para "bar" ]
1051+ , "Two blank lines after verse" =:
1052+ T.unlines
1053+ [ " - > foo"
1054+ , ""
1055+ , ""
1056+ , " - bar"
1057+ ] =?>
1058+ bulletList [ lineBlock [ "foo" ] ] <> bulletList [ para "bar" ]
1059+ ]
1060+ -- Test that definition list requires a leading space.
1061+ -- Emacs Muse does not require a space, we follow Amusewiki here.
1062+ , "Not a definition list" =:
1063+ T.unlines
1064+ [ "First :: second"
1065+ , "Foo :: bar"
1066+ ] =?>
1067+ para "First :: second\nFoo :: bar"
1068+ , test emacsMuse "Emacs Muse definition list"
1069+ (T.unlines
1070+ [ "First :: second"
1071+ , "Foo :: bar"
1072+ ] =?>
1073+ definitionList [ ("First", [ para "second" ])
1074+ , ("Foo", [ para "bar" ])
1075+ ])
1076+ , "Definition list" =:
1077+ T.unlines
1078+ [ " First :: second"
1079+ , " Foo :: bar"
1080+ ] =?>
1081+ definitionList [ ("First", [ para "second" ])
1082+ , ("Foo", [ para "bar" ])
1083+ ]
1084+ , "Definition list term cannot include newline" =:
1085+ T.unlines
1086+ [ " Foo" -- "Foo" is not a part of the definition list term
1087+ , " Bar :: baz"
1088+ ] =?>
1089+ para "Foo" <>
1090+ definitionList [ ("Bar", [ para "baz" ]) ]
1091+ , "One-line definition list" =: " foo :: bar" =?>
1092+ definitionList [ ("foo", [ para "bar" ]) ]
1093+ , "Definition list term may include single colon" =:
1094+ " foo:bar :: baz" =?>
1095+ definitionList [ ("foo:bar", [ para "baz" ]) ]
1096+ , "Definition list term with emphasis" =: " *Foo* :: bar\n" =?>
1097+ definitionList [ (emph "Foo", [ para "bar" ]) ]
1098+ , "Definition list term with :: inside code" =: " foo <code> :: </code> :: bar <code> :: </code> baz\n" =?>
1099+ definitionList [ ("foo " <> code " :: ", [ para $ "bar " <> code " :: " <> " baz" ]) ]
1100+ , "Multi-line definition lists" =:
1101+ T.unlines
1102+ [ " First term :: Definition of first term"
1103+ , "and its continuation."
1104+ , " Second term :: Definition of second term."
1105+ ] =?>
1106+ definitionList [ ("First term", [ para "Definition of first term\nand its continuation." ])
1107+ , ("Second term", [ para "Definition of second term." ])
1108+ ]
1109+ , test emacsMuse "Multi-line definition lists from Emacs Muse manual"
1110+ (T.unlines
1111+ [ "Term1 ::"
1112+ , " This is a first definition"
1113+ , " And it has two lines;"
1114+ , "no, make that three."
1115+ , ""
1116+ , "Term2 :: This is a second definition"
1117+ ] =?>
1118+ definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."])
1119+ , ("Term2", [ para "This is a second definition"])
1120+ ])
1121+ -- Text::Amuse requires indentation with one space
1122+ , "Multi-line definition lists from Emacs Muse manual with initial space" =:
1123+ (T.unlines
1124+ [ " Term1 ::"
1125+ , " This is a first definition"
1126+ , " And it has two lines;"
1127+ , "no, make that three."
1128+ , ""
1129+ , " Term2 :: This is a second definition"
1130+ ] =?>
1131+ definitionList [ ("Term1", [ para "This is a first definition\nAnd it has two lines;\nno, make that three."])
1132+ , ("Term2", [ para "This is a second definition"])
1133+ ])
1134+ , "One-line nested definition list" =:
1135+ " Foo :: bar :: baz" =?>
1136+ definitionList [ ("Foo", [ definitionList [ ("bar", [ para "baz" ])]])]
1137+ , "Nested definition list" =:
1138+ T.unlines
1139+ [ " First :: Second :: Third"
1140+ , " Fourth :: Fifth :: Sixth"
1141+ , " Seventh :: Eighth"
1142+ ] =?>
1143+ definitionList [ ("First", [ definitionList [ ("Second", [ para "Third" ]),
1144+ ("Fourth", [ definitionList [ ("Fifth", [ para "Sixth"] ) ] ] ) ] ] )
1145+ , ("Seventh", [ para "Eighth" ])
1146+ ]
1147+ , testGroup "Definition lists with multiple descriptions"
1148+ [ "Correctly indented second description" =:
1149+ T.unlines
1150+ [ " First term :: first description"
1151+ , " :: second description"
1152+ ] =?>
1153+ definitionList [ ("First term", [ para "first description"
1154+ , para "second description"
1155+ ])
1156+ ]
1157+ , "Incorrectly indented second description" =:
1158+ T.unlines
1159+ [ " First term :: first description"
1160+ , " :: second description"
1161+ ] =?>
1162+ definitionList [ ("First term", [ para "first description" ])
1163+ , ("", [ para "second description" ])
1164+ ]
1165+ ]
1166+ , "Two blank lines separate definition lists" =:
1167+ T.unlines
1168+ [ " First :: list"
1169+ , ""
1170+ , ""
1171+ , " Second :: list"
1172+ ] =?>
1173+ definitionList [ ("First", [ para "list" ]) ] <>
1174+ definitionList [ ("Second", [ para "list" ]) ]
1175+ -- Headers in first column of list continuation are not allowed
1176+ , "No headers in list continuation" =:
1177+ T.unlines
1178+ [ " - Foo"
1179+ , ""
1180+ , " * Bar"
1181+ ] =?>
1182+ bulletList [ mconcat [ para "Foo"
1183+ , para "* Bar"
1184+ ]
1185+ ]
1186+ , "Bullet list inside a tag" =:
1187+ T.unlines
1188+ [ "<quote>"
1189+ , " - First"
1190+ , ""
1191+ , " - Second"
1192+ , ""
1193+ , " - Third"
1194+ , "</quote>"
1195+ ] =?>
1196+ blockQuote (bulletList [ para "First"
1197+ , para "Second"
1198+ , para "Third"
1199+ ])
1200+ , "Ordered list inside a tag" =:
1201+ T.unlines
1202+ [ "<quote>"
1203+ , " 1. First"
1204+ , ""
1205+ , " 2. Second"
1206+ , ""
1207+ , " 3. Third"
1208+ , "</quote>"
1209+ ] =?>
1210+ blockQuote (orderedListWith (1, Decimal, Period) [ para "First"
1211+ , para "Second"
1212+ , para "Third"
1213+ ])
1214+ -- Regression test for a bug caught by round-trip test
1215+ , "Do not consume whitespace while looking for end tag" =:
1216+ T.unlines
1217+ [ "<quote>"
1218+ , " - <quote>"
1219+ , " foo"
1220+ , " </quote>"
1221+ , " bar" -- Do not consume whitespace while looking for arbitraritly indented </quote>
1222+ , "</quote>"
1223+ ] =?>
1224+ blockQuote (bulletList [ blockQuote $ para "foo" ] <> para "bar")
1225+
1226+ , "Unclosed quote tag" =:
1227+ T.unlines
1228+ [ "<quote>"
1229+ , "<verse>"
1230+ , "</quote>"
1231+ , "</verse>"
1232+ ] =?>
1233+ para "<quote>" <> lineBlock [ "</quote>" ]
1234+
1235+ , "Unclosed quote tag inside list" =:
1236+ T.unlines
1237+ [ " - <quote>"
1238+ , " <verse>"
1239+ , " </quote>"
1240+ , " </verse>"
1241+ ] =?>
1242+ bulletList [ para "<quote>" <> lineBlock [ "</quote>" ] ]
1243+
1244+ -- Allowing indented closing tags is dangerous,
1245+ -- as they may terminate lists
1246+ , "No indented closing tags" =:
1247+ T.unlines
1248+ [ "<quote>"
1249+ , ""
1250+ , " - Foo"
1251+ , ""
1252+ , " </quote>"
1253+ , ""
1254+ , " bar"
1255+ , ""
1256+ , " <verse>"
1257+ , " </quote>"
1258+ , " </verse>"
1259+ ] =?>
1260+ para "<quote>" <> bulletList [ para "Foo" <> para "</quote>" <> para "bar" <> lineBlock [ "</quote>" ] ]
1261+ ]
1262+ ]
test/Tests/Readers/Odt.hs+2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Readers.Odt (tests) where
23
4+import Prelude
35import Control.Monad (liftM)
46import qualified Data.ByteString as BS
57import qualified Data.ByteString.Lazy as B
test/Tests/Readers/Odt.hs.orignew file+170
@@ -0,0 +1,170 @@
1+module Tests.Readers.Odt (tests) where
2+
3+import Control.Monad (liftM)
4+import qualified Data.ByteString as BS
5+import qualified Data.ByteString.Lazy as B
6+import qualified Data.Map as M
7+import Data.Text (unpack)
8+import System.IO.Unsafe (unsafePerformIO)
9+import Test.Tasty
10+import Tests.Helpers
11+import Text.Pandoc
12+import qualified Text.Pandoc.UTF8 as UTF8
13+
14+defopts :: ReaderOptions
15+defopts = def{ readerExtensions = getDefaultExtensions "odt" }
16+
17+tests :: [TestTree]
18+tests = testsComparingToMarkdown ++ testsComparingToNative
19+
20+testsComparingToMarkdown :: [TestTree]
21+testsComparingToMarkdown = map nameToTest namesOfTestsComparingToMarkdown
22+ where nameToTest name = createTest
23+ compareOdtToMarkdown
24+ name
25+ (toOdtPath name)
26+ (toMarkdownPath name)
27+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
28+ toMarkdownPath name = "odt/markdown/" ++ name ++ ".md"
29+
30+testsComparingToNative :: [TestTree]
31+testsComparingToNative = map nameToTest namesOfTestsComparingToNative
32+ where nameToTest name = createTest
33+ compareOdtToNative
34+ name
35+ (toOdtPath name)
36+ (toNativePath name)
37+ toOdtPath name = "odt/odt/" ++ name ++ ".odt"
38+ toNativePath name = "odt/native/" ++ name ++ ".native"
39+
40+
41+newtype NoNormPandoc = NoNormPandoc {unNoNorm :: Pandoc}
42+ deriving ( Show )
43+
44+instance ToString NoNormPandoc where
45+ toString d = unpack $
46+ purely (writeNative def{ writerTemplate = s }) $ toPandoc d
47+ where s = case d of
48+ NoNormPandoc (Pandoc (Meta m) _)
49+ | M.null m -> Nothing
50+ | otherwise -> Just "" -- need this for Meta output
51+
52+instance ToPandoc NoNormPandoc where
53+ toPandoc = unNoNorm
54+
55+getNoNormVia :: (a -> Pandoc) -> String -> Either PandocError a -> NoNormPandoc
56+getNoNormVia _ readerName (Left _) = error (readerName ++ " reader failed")
57+getNoNormVia f _ (Right a) = NoNormPandoc (f a)
58+
59+type TestCreator = ReaderOptions
60+ -> FilePath -> FilePath
61+ -> IO (NoNormPandoc, NoNormPandoc)
62+
63+compareOdtToNative :: TestCreator
64+compareOdtToNative opts odtPath nativePath = do
65+ nativeFile <- UTF8.toText <$> BS.readFile nativePath
66+ odtFile <- B.readFile odtPath
67+ native <- getNoNormVia id "native" <$> runIO (readNative def nativeFile)
68+ odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile)
69+ return (odt,native)
70+
71+compareOdtToMarkdown :: TestCreator
72+compareOdtToMarkdown opts odtPath markdownPath = do
73+ markdownFile <- UTF8.toText <$> BS.readFile markdownPath
74+ odtFile <- B.readFile odtPath
75+ markdown <- getNoNormVia id "markdown" <$>
76+ runIO (readMarkdown def{ readerExtensions = pandocExtensions }
77+ markdownFile)
78+ odt <- getNoNormVia id "odt" <$> runIO (readOdt opts odtFile)
79+ return (odt,markdown)
80+
81+
82+createTest :: TestCreator
83+ -> TestName
84+ -> FilePath -> FilePath
85+ -> TestTree
86+createTest creator name path1 path2 =
87+ unsafePerformIO $ liftM (test id name) (creator defopts path1 path2)
88+
89+{-
90+--
91+
92+getMedia :: FilePath -> FilePath -> IO (Maybe B.ByteString)
93+getMedia archivePath mediaPath = do
94+ zf <- B.readFile archivePath >>= return . toArchive
95+ return $ findEntryByPath ("Pictures/" ++ mediaPath) zf >>= (Just . fromEntry)
96+
97+compareMediaPathIO :: FilePath -> MediaBag -> FilePath -> IO Bool
98+compareMediaPathIO mediaPath mediaBag odtPath = do
99+ odtMedia <- getMedia odtPath mediaPath
100+ let mbBS = case lookupMedia mediaPath mediaBag of
101+ Just (_, bs) -> bs
102+ Nothing -> error ("couldn't find " ++
103+ mediaPath ++
104+ " in media bag")
105+ odtBS = case odtMedia of
106+ Just bs -> bs
107+ Nothing -> error ("couldn't find " ++
108+ mediaPath ++
109+ " in media bag")
110+ return $ mbBS == odtBS
111+
112+compareMediaBagIO :: FilePath -> IO Bool
113+compareMediaBagIO odtFile = do
114+ df <- B.readFile odtFile
115+ let (_, mb) = readOdt def df
116+ bools <- mapM
117+ (\(fp, _, _) -> compareMediaPathIO fp mb odtFile)
118+ (mediaDirectory mb)
119+ return $ and bools
120+
121+testMediaBagIO :: String -> FilePath -> IO TestTree
122+testMediaBagIO name odtFile = do
123+ outcome <- compareMediaBagIO odtFile
124+ return $ testCase name (assertBool
125+ ("Media didn't match media bag in file " ++ odtFile)
126+ outcome)
127+
128+testMediaBag :: String -> FilePath -> TestTree
129+testMediaBag name odtFile = buildTest $ testMediaBagIO name odtFile
130+-}
131+--
132+
133+
134+
135+namesOfTestsComparingToMarkdown :: [ String ]
136+namesOfTestsComparingToMarkdown = [ "bold"
137+-- , "citation"
138+ , "endnote"
139+ , "externalLink"
140+ , "footnote"
141+ , "headers"
142+-- , "horizontalRule"
143+ , "italic"
144+-- , "listBlocks"
145+ , "paragraph"
146+ , "strikeout"
147+-- , "trackedChanges"
148+ , "underlined"
149+ ]
150+
151+namesOfTestsComparingToNative :: [ String ]
152+namesOfTestsComparingToNative = [ "blockquote"
153+ , "image"
154+ , "imageIndex"
155+ , "imageWithCaption"
156+ , "inlinedCode"
157+ , "orderedListMixed"
158+ , "orderedListRoman"
159+ , "orderedListSimple"
160+ , "referenceToChapter"
161+ , "referenceToListItem"
162+ , "referenceToText"
163+ , "simpleTable"
164+ , "simpleTableWithCaption"
165+-- , "table"
166+ , "textMixedStyles"
167+ , "tableWithContents"
168+ , "unicode"
169+ , "unorderedList"
170+ ]
test/Tests/Readers/Org.hs.orignew file+16
@@ -0,0 +1,16 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org (tests) where
3+
4+import Test.Tasty (TestTree, testGroup)
5+import qualified Tests.Readers.Org.Block as Block
6+import qualified Tests.Readers.Org.Directive as Directive
7+import qualified Tests.Readers.Org.Inline as Inline
8+import qualified Tests.Readers.Org.Meta as Meta
9+
10+tests :: [TestTree]
11+tests =
12+ [ testGroup "Inlines" Inline.tests
13+ , testGroup "Basic Blocks" Block.tests
14+ , testGroup "Meta Information" Meta.tests
15+ , testGroup "Directives" Directive.tests
16+ ]
test/Tests/Readers/Org/Block.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree, testGroup)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep)
test/Tests/Readers/Org/Block.hs.orignew file+192
@@ -0,0 +1,192 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block (tests) where
3+
4+import Test.Tasty (TestTree, testGroup)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep)
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+import qualified Tests.Readers.Org.Block.CodeBlock as CodeBlock
10+import qualified Tests.Readers.Org.Block.Figure as Figure
11+import qualified Tests.Readers.Org.Block.Header as Header
12+import qualified Tests.Readers.Org.Block.List as List
13+import qualified Tests.Readers.Org.Block.Table as Table
14+
15+tests :: [TestTree]
16+tests =
17+ [ "Paragraph" =:
18+ "Paragraph\n" =?>
19+ para "Paragraph"
20+
21+ , "Paragraph starting with an asterisk" =:
22+ "*five" =?>
23+ para "*five"
24+
25+ , "Paragraph containing asterisk at beginning of line" =:
26+ T.unlines [ "lucky"
27+ , "*star"
28+ ] =?>
29+ para ("lucky" <> softbreak <> "*star")
30+
31+ , "Example block" =:
32+ T.unlines [ ": echo hello"
33+ , ": echo dear tester"
34+ ] =?>
35+ codeBlockWith ("", ["example"], []) "echo hello\necho dear tester\n"
36+
37+ , "Example block surrounded by text" =:
38+ T.unlines [ "Greetings"
39+ , ": echo hello"
40+ , ": echo dear tester"
41+ , "Bye"
42+ ] =?>
43+ mconcat [ para "Greetings"
44+ , codeBlockWith ("", ["example"], [])
45+ "echo hello\necho dear tester\n"
46+ , para "Bye"
47+ ]
48+
49+ , "Horizontal Rule" =:
50+ T.unlines [ "before"
51+ , "-----"
52+ , "after"
53+ ] =?>
54+ mconcat [ para "before"
55+ , horizontalRule
56+ , para "after"
57+ ]
58+
59+ , "Not a Horizontal Rule" =:
60+ "----- em and en dash" =?>
61+ para "\8212\8211 em and en dash"
62+
63+ , "Comment Block" =:
64+ T.unlines [ "#+BEGIN_COMMENT"
65+ , "stuff"
66+ , "bla"
67+ , "#+END_COMMENT"] =?>
68+ (mempty::Blocks)
69+
70+ , testGroup "Blocks and fragments"
71+ [ "HTML block" =:
72+ T.unlines [ "#+BEGIN_HTML"
73+ , "<aside>HTML5 is pretty nice.</aside>"
74+ , "#+END_HTML"
75+ ] =?>
76+ rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
77+
78+ , "Quote block" =:
79+ T.unlines [ "#+BEGIN_QUOTE"
80+ , "/Niemand/ hat die Absicht, eine Mauer zu errichten!"
81+ , "#+END_QUOTE"
82+ ] =?>
83+ blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
84+ , "eine", "Mauer", "zu", "errichten!"
85+ ]))
86+
87+ , "Verse block" =:
88+ T.unlines [ "The first lines of Goethe's /Faust/:"
89+ , "#+begin_verse"
90+ , "Habe nun, ach! Philosophie,"
91+ , "Juristerei und Medizin,"
92+ , "Und leider auch Theologie!"
93+ , "Durchaus studiert, mit heißem Bemühn."
94+ , "#+end_verse"
95+ ] =?>
96+ mconcat
97+ [ para $ spcSep [ "The", "first", "lines", "of"
98+ , "Goethe's", emph "Faust" <> ":"]
99+ , lineBlock
100+ [ "Habe nun, ach! Philosophie,"
101+ , "Juristerei und Medizin,"
102+ , "Und leider auch Theologie!"
103+ , "Durchaus studiert, mit heißem Bemühn."
104+ ]
105+ ]
106+
107+ , "Verse block with blank lines" =:
108+ T.unlines [ "#+BEGIN_VERSE"
109+ , "foo"
110+ , ""
111+ , "bar"
112+ , "#+END_VERSE"
113+ ] =?>
114+ lineBlock [ "foo", mempty, "bar" ]
115+
116+ , "Verse block with varying indentation" =:
117+ T.unlines [ "#+BEGIN_VERSE"
118+ , " hello darkness"
119+ , "my old friend"
120+ , "#+END_VERSE"
121+ ] =?>
122+ lineBlock [ "\160\160hello darkness", "my old friend" ]
123+
124+ , "Raw block LaTeX" =:
125+ T.unlines [ "#+BEGIN_LaTeX"
126+ , "The category $\\cat{Set}$ is adhesive."
127+ , "#+END_LaTeX"
128+ ] =?>
129+ rawBlock "latex" "The category $\\cat{Set}$ is adhesive.\n"
130+
131+ , "Raw LaTeX line" =:
132+ "#+LATEX: \\let\\foo\\bar" =?>
133+ rawBlock "latex" "\\let\\foo\\bar"
134+
135+ , "Raw Beamer line" =:
136+ "#+beamer: \\pause" =?>
137+ rawBlock "beamer" "\\pause"
138+
139+ , "Raw HTML line" =:
140+ "#+HTML: <aside>not important</aside>" =?>
141+ rawBlock "html" "<aside>not important</aside>"
142+
143+ , "Export block HTML" =:
144+ T.unlines [ "#+BEGIN_export html"
145+ , "<samp>Hello, World!</samp>"
146+ , "#+END_export"
147+ ] =?>
148+ rawBlock "html" "<samp>Hello, World!</samp>\n"
149+
150+ , "LaTeX fragment" =:
151+ T.unlines [ "\\begin{equation}"
152+ , "X_i = \\begin{cases}"
153+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) = \\alpha(i)\\\\"
154+ , " C_{\\alpha(i)} & \\text{otherwise}"
155+ , " \\end{cases}"
156+ , "\\end{equation}"
157+ ] =?>
158+ rawBlock "latex"
159+ (unlines [ "\\begin{equation}"
160+ , "X_i = \\begin{cases}"
161+ , " G_{\\alpha(i)} & \\text{if }\\alpha(i-1) =" <>
162+ " \\alpha(i)\\\\"
163+ , " C_{\\alpha(i)} & \\text{otherwise}"
164+ , " \\end{cases}"
165+ , "\\end{equation}"
166+ ])
167+
168+ , "Convert blank lines in blocks to single newlines" =:
169+ T.unlines [ "#+begin_html"
170+ , ""
171+ , "<span>boring</span>"
172+ , ""
173+ , "#+end_html"
174+ ] =?>
175+ rawBlock "html" "\n<span>boring</span>\n\n"
176+
177+ , "Accept `ATTR_HTML` attributes for generic block" =:
178+ T.unlines [ "#+ATTR_HTML: :title hello, world :id test :class fun code"
179+ , "#+BEGIN_TEST"
180+ , "nonsense"
181+ , "#+END_TEST"
182+ ] =?>
183+ let attr = ("test", ["fun", "code", "TEST"], [("title", "hello, world")])
184+ in divWith attr (para "nonsense")
185+ ]
186+
187+ , testGroup "Headers" Header.tests
188+ , testGroup "Figures" Figure.tests
189+ , testGroup "Lists" List.tests
190+ , testGroup "CodeBlocks" CodeBlock.tests
191+ , testGroup "Tables" Table.tests
192+ ]
test/Tests/Readers/Org/Block/CodeBlock.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block.CodeBlock (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep)
test/Tests/Readers/Org/Block/CodeBlock.hs.orignew file+194
@@ -0,0 +1,194 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block.CodeBlock (tests) where
3+
4+import Test.Tasty (TestTree)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep)
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+
10+tests :: [TestTree]
11+tests =
12+ [ "Source block" =:
13+ T.unlines [ " #+BEGIN_SRC haskell"
14+ , " main = putStrLn greeting"
15+ , " where greeting = \"moin\""
16+ , " #+END_SRC" ] =?>
17+ let attr' = ("", ["haskell"], [])
18+ code' = "main = putStrLn greeting\n" <>
19+ " where greeting = \"moin\"\n"
20+ in codeBlockWith attr' code'
21+
22+ , "Source block with indented code" =:
23+ T.unlines [ " #+BEGIN_SRC haskell"
24+ , " main = putStrLn greeting"
25+ , " where greeting = \"moin\""
26+ , " #+END_SRC" ] =?>
27+ let attr' = ("", ["haskell"], [])
28+ code' = "main = putStrLn greeting\n" <>
29+ " where greeting = \"moin\"\n"
30+ in codeBlockWith attr' code'
31+
32+ , "Source block with tab-indented code" =:
33+ T.unlines [ "\t#+BEGIN_SRC haskell"
34+ , "\tmain = putStrLn greeting"
35+ , "\t where greeting = \"moin\""
36+ , "\t#+END_SRC" ] =?>
37+ let attr' = ("", ["haskell"], [])
38+ code' = "main = putStrLn greeting\n" <>
39+ " where greeting = \"moin\"\n"
40+ in codeBlockWith attr' code'
41+
42+ , "Empty source block" =:
43+ T.unlines [ " #+BEGIN_SRC haskell"
44+ , " #+END_SRC" ] =?>
45+ let attr' = ("", ["haskell"], [])
46+ code' = ""
47+ in codeBlockWith attr' code'
48+
49+ , "Source block between paragraphs" =:
50+ T.unlines [ "Low German greeting"
51+ , " #+BEGIN_SRC haskell"
52+ , " main = putStrLn greeting"
53+ , " where greeting = \"Moin!\""
54+ , " #+END_SRC" ] =?>
55+ let attr' = ("", ["haskell"], [])
56+ code' = "main = putStrLn greeting\n" <>
57+ " where greeting = \"Moin!\"\n"
58+ in mconcat [ para $ spcSep [ "Low", "German", "greeting" ]
59+ , codeBlockWith attr' code'
60+ ]
61+ , "Source block with babel arguments" =:
62+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
63+ , "(progn (message \"Hello, World!\")"
64+ , " (+ 23 42))"
65+ , "#+END_SRC" ] =?>
66+ let classes = [ "commonlisp" ] -- as kate doesn't know emacs-lisp syntax
67+ params = [ ("org-language", "emacs-lisp")
68+ , ("exports", "both")
69+ ]
70+ code' = unlines [ "(progn (message \"Hello, World!\")"
71+ , " (+ 23 42))" ]
72+ in codeBlockWith ("", classes, params) code'
73+
74+ , "Source block with results and :exports both" =:
75+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports both"
76+ , "(progn (message \"Hello, World!\")"
77+ , " (+ 23 42))"
78+ , "#+END_SRC"
79+ , ""
80+ , "#+RESULTS:"
81+ , ": 65"] =?>
82+ let classes = [ "commonlisp" ]
83+ params = [ ("org-language", "emacs-lisp")
84+ , ("exports", "both")
85+ ]
86+ code' = unlines [ "(progn (message \"Hello, World!\")"
87+ , " (+ 23 42))" ]
88+ results' = "65\n"
89+ in codeBlockWith ("", classes, params) code'
90+ <>
91+ codeBlockWith ("", ["example"], []) results'
92+
93+ , "Source block with results and :exports code" =:
94+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports code"
95+ , "(progn (message \"Hello, World!\")"
96+ , " (+ 23 42))"
97+ , "#+END_SRC"
98+ , ""
99+ , "#+RESULTS:"
100+ , ": 65" ] =?>
101+ let classes = [ "commonlisp" ]
102+ params = [ ("org-language", "emacs-lisp")
103+ , ("exports", "code")
104+ ]
105+ code' = unlines [ "(progn (message \"Hello, World!\")"
106+ , " (+ 23 42))" ]
107+ in codeBlockWith ("", classes, params) code'
108+
109+ , "Source block with results and :exports results" =:
110+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports results"
111+ , "(progn (message \"Hello, World!\")"
112+ , " (+ 23 42))"
113+ , "#+END_SRC"
114+ , ""
115+ , "#+RESULTS:"
116+ , ": 65" ] =?>
117+ let results' = "65\n"
118+ in codeBlockWith ("", ["example"], []) results'
119+
120+ , "Source block with results and :exports none" =:
121+ T.unlines [ "#+BEGIN_SRC emacs-lisp :exports none"
122+ , "(progn (message \"Hello, World!\")"
123+ , " (+ 23 42))"
124+ , "#+END_SRC"
125+ , ""
126+ , "#+RESULTS:"
127+ , ": 65" ] =?>
128+ (mempty :: Blocks)
129+
130+ , "Source block with toggling header arguments" =:
131+ T.unlines [ "#+BEGIN_SRC sh :noeval"
132+ , "echo $HOME"
133+ , "#+END_SRC"
134+ ] =?>
135+ let classes = [ "bash" ]
136+ params = [ ("org-language", "sh"), ("noeval", "yes") ]
137+ in codeBlockWith ("", classes, params) "echo $HOME\n"
138+
139+ , "Source block with line number switch" =:
140+ T.unlines [ "#+BEGIN_SRC sh -n 10"
141+ , ":() { :|:& };:"
142+ , "#+END_SRC"
143+ ] =?>
144+ let classes = [ "bash", "numberLines" ]
145+ params = [ ("org-language", "sh"), ("startFrom", "10") ]
146+ in codeBlockWith ("", classes, params) ":() { :|:& };:\n"
147+
148+ , "Source block with multi-word parameter values" =:
149+ T.unlines [ "#+BEGIN_SRC dot :cmdline -Kdot -Tpng "
150+ , "digraph { id [label=\"ID\"] }"
151+ , "#+END_SRC"
152+ ] =?>
153+ let classes = [ "dot" ]
154+ params = [ ("cmdline", "-Kdot -Tpng") ]
155+ in codeBlockWith ("", classes, params) "digraph { id [label=\"ID\"] }\n"
156+
157+ , "Example block" =:
158+ T.unlines [ "#+begin_example"
159+ , "A chosen representation of"
160+ , "a rule."
161+ , "#+eND_exAMPle"
162+ ] =?>
163+ codeBlockWith ("", ["example"], [])
164+ "A chosen representation of\na rule.\n"
165+
166+ , "Code block with caption" =:
167+ T.unlines [ "#+CAPTION: Functor laws in Haskell"
168+ , "#+NAME: functor-laws"
169+ , "#+BEGIN_SRC haskell"
170+ , "fmap id = id"
171+ , "fmap (p . q) = (fmap p) . (fmap q)"
172+ , "#+END_SRC"
173+ ] =?>
174+ divWith
175+ nullAttr
176+ (mappend
177+ (plain $ spanWith ("", ["label"], [])
178+ (spcSep [ "Functor", "laws", "in", "Haskell" ]))
179+ (codeBlockWith ("functor-laws", ["haskell"], [])
180+ (unlines [ "fmap id = id"
181+ , "fmap (p . q) = (fmap p) . (fmap q)"
182+ ])))
183+
184+ , "Non-letter chars in source block parameters" =:
185+ T.unlines [ "#+BEGIN_SRC C :tangle xxxx.c :city Zürich"
186+ , "code body"
187+ , "#+END_SRC"
188+ ] =?>
189+ let params = [ ("org-language", "C")
190+ , ("tangle", "xxxx.c")
191+ , ("city", "Zürich")
192+ ]
193+ in codeBlockWith ( "", ["c"], params) "code body\n"
194+ ]
test/Tests/Readers/Org/Block/Figure.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block.Figure (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:))
test/Tests/Readers/Org/Block/Figure.hs.orignew file+57
@@ -0,0 +1,57 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block.Figure (tests) where
3+
4+import Test.Tasty (TestTree)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:))
7+import Text.Pandoc.Builder (image, imageWith, para)
8+import qualified Data.Text as T
9+
10+tests :: [TestTree]
11+tests =
12+ [ "Figure" =:
13+ T.unlines [ "#+caption: A very courageous man."
14+ , "#+name: goodguy"
15+ , "[[file:edward.jpg]]"
16+ ] =?>
17+ para (image "edward.jpg" "fig:goodguy" "A very courageous man.")
18+
19+ , "Figure with no name" =:
20+ T.unlines [ "#+caption: I've been through the desert on this"
21+ , "[[file:horse.png]]"
22+ ] =?>
23+ para (image "horse.png" "fig:" "I've been through the desert on this")
24+
25+ , "Figure with `fig:` prefix in name" =:
26+ T.unlines [ "#+caption: Used as a metapher in evolutionary biology."
27+ , "#+name: fig:redqueen"
28+ , "[[./the-red-queen.jpg]]"
29+ ] =?>
30+ para (image "./the-red-queen.jpg" "fig:redqueen"
31+ "Used as a metapher in evolutionary biology.")
32+
33+ , "Figure with HTML attributes" =:
34+ T.unlines [ "#+CAPTION: mah brain just explodid"
35+ , "#+NAME: lambdacat"
36+ , "#+ATTR_HTML: :style color: blue :role button"
37+ , "[[file:lambdacat.jpg]]"
38+ ] =?>
39+ let kv = [("style", "color: blue"), ("role", "button")]
40+ name = "fig:lambdacat"
41+ caption = "mah brain just explodid"
42+ in para (imageWith (mempty, mempty, kv) "lambdacat.jpg" name caption)
43+
44+ , "Labelled figure" =:
45+ T.unlines [ "#+CAPTION: My figure"
46+ , "#+LABEL: fig:myfig"
47+ , "[[file:blub.png]]"
48+ ] =?>
49+ let attr = ("fig:myfig", mempty, mempty)
50+ in para (imageWith attr "blub.png" "fig:" "My figure")
51+
52+ , "Figure with empty caption" =:
53+ T.unlines [ "#+CAPTION:"
54+ , "[[file:guess.jpg]]"
55+ ] =?>
56+ para (image "guess.jpg" "fig:" "")
57+ ]
test/Tests/Readers/Org/Block/Header.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block.Header (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree, testGroup)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep, tagSpan)
test/Tests/Readers/Org/Block/Header.hs.orignew file+182
@@ -0,0 +1,182 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block.Header (tests) where
3+
4+import Test.Tasty (TestTree, testGroup)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep, tagSpan)
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+
10+tests :: [TestTree]
11+tests =
12+ [ "First Level Header" =:
13+ "* Headline\n" =?>
14+ headerWith ("headline", [], []) 1 "Headline"
15+
16+ , "Third Level Header" =:
17+ "*** Third Level Headline\n" =?>
18+ headerWith ("third-level-headline", [], [])
19+ 3
20+ ("Third" <> space <> "Level" <> space <> "Headline")
21+
22+ , "Compact Headers with Paragraph" =:
23+ T.unlines [ "* First Level"
24+ , "** Second Level"
25+ , " Text"
26+ ] =?>
27+ mconcat [ headerWith ("first-level", [], [])
28+ 1
29+ ("First" <> space <> "Level")
30+ , headerWith ("second-level", [], [])
31+ 2
32+ ("Second" <> space <> "Level")
33+ , para "Text"
34+ ]
35+
36+ , "Separated Headers with Paragraph" =:
37+ T.unlines [ "* First Level"
38+ , ""
39+ , "** Second Level"
40+ , ""
41+ , " Text"
42+ ] =?>
43+ mconcat [ headerWith ("first-level", [], [])
44+ 1
45+ ("First" <> space <> "Level")
46+ , headerWith ("second-level", [], [])
47+ 2
48+ ("Second" <> space <> "Level")
49+ , para "Text"
50+ ]
51+
52+ , "Headers not preceded by a blank line" =:
53+ T.unlines [ "** eat dinner"
54+ , "Spaghetti and meatballs tonight."
55+ , "** walk dog"
56+ ] =?>
57+ mconcat [ headerWith ("eat-dinner", [], [])
58+ 2
59+ ("eat" <> space <> "dinner")
60+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
61+ , headerWith ("walk-dog", [], [])
62+ 2
63+ ("walk" <> space <> "dog")
64+ ]
65+
66+ , testGroup "Todo keywords"
67+ [ "Header with known todo keyword" =:
68+ "* TODO header" =?>
69+ let todoSpan = spanWith ("", ["todo", "TODO"], []) "TODO"
70+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
71+
72+ , "Header marked as done" =:
73+ "* DONE header" =?>
74+ let todoSpan = spanWith ("", ["done", "DONE"], []) "DONE"
75+ in headerWith ("header", [], []) 1 (todoSpan <> space <> "header")
76+
77+ , "Header with unknown todo keyword" =:
78+ "* WAITING header" =?>
79+ headerWith ("waiting-header", [], []) 1 "WAITING header"
80+
81+ , "Custom todo keywords" =:
82+ T.unlines [ "#+TODO: WAITING CANCELLED"
83+ , "* WAITING compile"
84+ , "* CANCELLED lunch"
85+ ] =?>
86+ let todoSpan = spanWith ("", ["todo", "WAITING"], []) "WAITING"
87+ doneSpan = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
88+ in headerWith ("compile", [], []) 1 (todoSpan <> space <> "compile")
89+ <> headerWith ("lunch", [], []) 1 (doneSpan <> space <> "lunch")
90+
91+ , "Custom todo keywords with multiple done-states" =:
92+ T.unlines [ "#+TODO: WAITING | DONE CANCELLED "
93+ , "* WAITING compile"
94+ , "* CANCELLED lunch"
95+ , "* DONE todo-feature"
96+ ] =?>
97+ let waiting = spanWith ("", ["todo", "WAITING"], []) "WAITING"
98+ cancelled = spanWith ("", ["done", "CANCELLED"], []) "CANCELLED"
99+ done = spanWith ("", ["done", "DONE"], []) "DONE"
100+ in headerWith ("compile", [], []) 1 (waiting <> space <> "compile")
101+ <> headerWith ("lunch", [], []) 1 (cancelled <> space <> "lunch")
102+ <> headerWith ("todo-feature", [], []) 1 (done <> space <> "todo-feature")
103+ ]
104+
105+ , "Tagged headers" =:
106+ T.unlines [ "* Personal :PERSONAL:"
107+ , "** Call Mom :@PHONE:"
108+ , "** Call John :@PHONE:JOHN: "
109+ ] =?>
110+ mconcat [ headerWith ("personal", [], [])
111+ 1
112+ ("Personal " <> tagSpan "PERSONAL")
113+ , headerWith ("call-mom", [], [])
114+ 2
115+ ("Call Mom " <> tagSpan "@PHONE")
116+ , headerWith ("call-john", [], [])
117+ 2
118+ ("Call John " <> tagSpan "@PHONE" <> "\160" <> tagSpan "JOHN")
119+ ]
120+
121+ , "Untagged header containing colons" =:
122+ "* This: is not: tagged" =?>
123+ headerWith ("this-is-not-tagged", [], []) 1 "This: is not: tagged"
124+
125+ , "Header starting with strokeout text" =:
126+ T.unlines [ "foo"
127+ , ""
128+ , "* +thing+ other thing"
129+ ] =?>
130+ mconcat [ para "foo"
131+ , headerWith ("thing-other-thing", [], [])
132+ 1
133+ (strikeout "thing" <> " other thing")
134+ ]
135+
136+ , "Comment Trees" =:
137+ T.unlines [ "* COMMENT A comment tree"
138+ , " Not much going on here"
139+ , "** This will be dropped"
140+ , "* Comment tree above"
141+ ] =?>
142+ headerWith ("comment-tree-above", [], []) 1 "Comment tree above"
143+
144+ , "Nothing but a COMMENT header" =:
145+ "* COMMENT Test" =?>
146+ (mempty::Blocks)
147+
148+ , "Tree with :noexport:" =:
149+ T.unlines [ "* Should be ignored :archive:noexport:old:"
150+ , "** Old stuff"
151+ , " This is not going to be exported"
152+ ] =?>
153+ (mempty::Blocks)
154+
155+ , "Subtree with :noexport:" =:
156+ T.unlines [ "* Exported"
157+ , "** This isn't exported :noexport:"
158+ , "*** This neither"
159+ , "** But this is"
160+ ] =?>
161+ mconcat [ headerWith ("exported", [], []) 1 "Exported"
162+ , headerWith ("but-this-is", [], []) 2 "But this is"
163+ ]
164+
165+ , "Preferences are treated as header attributes" =:
166+ T.unlines [ "* foo"
167+ , " :PROPERTIES:"
168+ , " :custom_id: fubar"
169+ , " :bar: baz"
170+ , " :END:"
171+ ] =?>
172+ headerWith ("fubar", [], [("bar", "baz")]) 1 "foo"
173+
174+
175+ , "Headers marked with a unnumbered property get a class of the same name" =:
176+ T.unlines [ "* Not numbered"
177+ , " :PROPERTIES:"
178+ , " :UNNUMBERED: t"
179+ , " :END:"
180+ ] =?>
181+ headerWith ("not-numbered", ["unnumbered"], []) 1 "Not numbered"
182+ ]
test/Tests/Readers/Org/Block/List.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block.List (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep)
test/Tests/Readers/Org/Block/List.hs.orignew file+244
@@ -0,0 +1,244 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block.List (tests) where
3+
4+import Test.Tasty (TestTree)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep)
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+
10+tests :: [TestTree]
11+tests =
12+ [ "Simple Bullet Lists" =:
13+ ("- Item1\n" <>
14+ "- Item2\n") =?>
15+ bulletList [ plain "Item1"
16+ , plain "Item2"
17+ ]
18+
19+ , "Indented Bullet Lists" =:
20+ (" - Item1\n" <>
21+ " - Item2\n") =?>
22+ bulletList [ plain "Item1"
23+ , plain "Item2"
24+ ]
25+
26+ , "Unindented *" =:
27+ ("- Item1\n" <>
28+ "* Item2\n") =?>
29+ bulletList [ plain "Item1"
30+ ] <>
31+ headerWith ("item2", [], []) 1 "Item2"
32+
33+ , "Multi-line Bullet Lists" =:
34+ ("- *Fat\n" <>
35+ " Tony*\n" <>
36+ "- /Sideshow\n" <>
37+ " Bob/") =?>
38+ bulletList [ plain $ strong ("Fat" <> softbreak <> "Tony")
39+ , plain $ emph ("Sideshow" <> softbreak <> "Bob")
40+ ]
41+
42+ , "Nested Bullet Lists" =:
43+ ("- Discovery\n" <>
44+ " + One More Time\n" <>
45+ " + Harder, Better, Faster, Stronger\n" <>
46+ "- Homework\n" <>
47+ " + Around the World\n"<>
48+ "- Human After All\n" <>
49+ " + Technologic\n" <>
50+ " + Robot Rock\n") =?>
51+ bulletList [ mconcat
52+ [ plain "Discovery"
53+ , bulletList [ plain ("One" <> space <>
54+ "More" <> space <>
55+ "Time")
56+ , plain ("Harder," <> space <>
57+ "Better," <> space <>
58+ "Faster," <> space <>
59+ "Stronger")
60+ ]
61+ ]
62+ , mconcat
63+ [ plain "Homework"
64+ , bulletList [ plain ("Around" <> space <>
65+ "the" <> space <>
66+ "World")
67+ ]
68+ ]
69+ , mconcat
70+ [ plain ("Human" <> space <> "After" <> space <> "All")
71+ , bulletList [ plain "Technologic"
72+ , plain ("Robot" <> space <> "Rock")
73+ ]
74+ ]
75+ ]
76+
77+ , "Bullet List with Decreasing Indent" =:
78+ " - Discovery\n\
79+ \ - Human After All\n" =?>
80+ mconcat [ bulletList [ plain "Discovery" ]
81+ , bulletList [ plain ("Human" <> space <> "After" <> space <> "All")]
82+ ]
83+
84+ , "Header follows Bullet List" =:
85+ " - Discovery\n\
86+ \ - Human After All\n\
87+ \* Homework" =?>
88+ mconcat [ bulletList [ plain "Discovery"
89+ , plain ("Human" <> space <> "After" <> space <> "All")
90+ ]
91+ , headerWith ("homework", [], []) 1 "Homework"
92+ ]
93+
94+ , "Bullet List Unindented with trailing Header" =:
95+ "- Discovery\n\
96+ \- Homework\n\
97+ \* NotValidListItem" =?>
98+ mconcat [ bulletList [ plain "Discovery"
99+ , plain "Homework"
100+ ]
101+ , headerWith ("notvalidlistitem", [], []) 1 "NotValidListItem"
102+ ]
103+
104+ , "Empty bullet points" =:
105+ T.unlines [ "-"
106+ , "- "
107+ ] =?>
108+ bulletList [ plain "", plain "" ]
109+
110+ , "Simple Ordered List" =:
111+ ("1. Item1\n" <>
112+ "2. Item2\n") =?>
113+ let listStyle = (1, DefaultStyle, DefaultDelim)
114+ listStructure = [ plain "Item1"
115+ , plain "Item2"
116+ ]
117+ in orderedListWith listStyle listStructure
118+
119+ , "Simple Ordered List with Parens" =:
120+ ("1) Item1\n" <>
121+ "2) Item2\n") =?>
122+ let listStyle = (1, DefaultStyle, DefaultDelim)
123+ listStructure = [ plain "Item1"
124+ , plain "Item2"
125+ ]
126+ in orderedListWith listStyle listStructure
127+
128+ , "Indented Ordered List" =:
129+ (" 1. Item1\n" <>
130+ " 2. Item2\n") =?>
131+ let listStyle = (1, DefaultStyle, DefaultDelim)
132+ listStructure = [ plain "Item1"
133+ , plain "Item2"
134+ ]
135+ in orderedListWith listStyle listStructure
136+
137+ , "Empty ordered list item" =:
138+ T.unlines [ "1."
139+ , "3. "
140+ ] =?>
141+ orderedList [ plain "", plain "" ]
142+
143+ , "Nested Ordered Lists" =:
144+ ("1. One\n" <>
145+ " 1. One-One\n" <>
146+ " 2. One-Two\n" <>
147+ "2. Two\n" <>
148+ " 1. Two-One\n"<>
149+ " 2. Two-Two\n") =?>
150+ let listStyle = (1, DefaultStyle, DefaultDelim)
151+ listStructure = [ mconcat
152+ [ plain "One"
153+ , orderedList [ plain "One-One"
154+ , plain "One-Two"
155+ ]
156+ ]
157+ , mconcat
158+ [ plain "Two"
159+ , orderedList [ plain "Two-One"
160+ , plain "Two-Two"
161+ ]
162+ ]
163+ ]
164+ in orderedListWith listStyle listStructure
165+
166+ , "Ordered List in Bullet List" =:
167+ ("- Emacs\n" <>
168+ " 1. Org\n") =?>
169+ bulletList [ plain "Emacs" <>
170+ orderedList [ plain "Org"]
171+ ]
172+
173+ , "Bullet List in Ordered List" =:
174+ ("1. GNU\n" <>
175+ " - Freedom\n") =?>
176+ orderedList [ plain "GNU" <> bulletList [ plain "Freedom" ] ]
177+
178+ , "Definition List" =:
179+ T.unlines [ "- PLL :: phase-locked loop"
180+ , "- TTL ::"
181+ , " transistor-transistor logic"
182+ , "- PSK :: phase-shift keying"
183+ , ""
184+ , " a digital modulation scheme"
185+ ] =?>
186+ definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
187+ , ("TTL", [ plain $ "transistor-transistor" <> space <>
188+ "logic" ])
189+ , ("PSK", [ mconcat
190+ [ para $ "phase-shift" <> space <> "keying"
191+ , para $ spcSep [ "a", "digital"
192+ , "modulation", "scheme" ]
193+ ]
194+ ])
195+ ]
196+ , "Definition list with multi-word term" =:
197+ " - Elijah Wood :: He plays Frodo" =?>
198+ definitionList [ ("Elijah" <> space <> "Wood", [plain $ "He" <> space <> "plays" <> space <> "Frodo"])]
199+ , "Compact definition list" =:
200+ T.unlines [ "- ATP :: adenosine 5' triphosphate"
201+ , "- DNA :: deoxyribonucleic acid"
202+ , "- PCR :: polymerase chain reaction"
203+ , ""
204+ ] =?>
205+ definitionList
206+ [ ("ATP", [ plain $ spcSep [ "adenosine", "5'", "triphosphate" ] ])
207+ , ("DNA", [ plain $ spcSep [ "deoxyribonucleic", "acid" ] ])
208+ , ("PCR", [ plain $ spcSep [ "polymerase", "chain", "reaction" ] ])
209+ ]
210+
211+ , "Definition List With Trailing Header" =:
212+ "- definition :: list\n\
213+ \- cool :: defs\n\
214+ \* header" =?>
215+ mconcat [ definitionList [ ("definition", [plain "list"])
216+ , ("cool", [plain "defs"])
217+ ]
218+ , headerWith ("header", [], []) 1 "header"
219+ ]
220+
221+ , "Definition lists double-colon markers must be surrounded by whitespace" =:
222+ "- std::cout" =?>
223+ bulletList [ plain "std::cout" ]
224+
225+ , "Loose bullet list" =:
226+ T.unlines [ "- apple"
227+ , ""
228+ , "- orange"
229+ , ""
230+ , "- peach"
231+ ] =?>
232+ bulletList [ para "apple"
233+ , para "orange"
234+ , para "peach"
235+ ]
236+
237+ , "Recognize preceding paragraphs in non-list contexts" =:
238+ T.unlines [ "CLOSED: [2015-10-19 Mon 15:03]"
239+ , "- Note taken on [2015-10-19 Mon 13:24]"
240+ ] =?>
241+ mconcat [ para "CLOSED: [2015-10-19 Mon 15:03]"
242+ , bulletList [ plain "Note taken on [2015-10-19 Mon 13:24]" ]
243+ ]
244+ ]
test/Tests/Readers/Org/Block/Table.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Block.Table (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep)
test/Tests/Readers/Org/Block/Table.hs.orignew file+150
@@ -0,0 +1,150 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Block.Table (tests) where
3+
4+import Test.Tasty (TestTree)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep)
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+
10+simpleTable' :: Int
11+ -> [Blocks]
12+ -> [[Blocks]]
13+ -> Blocks
14+simpleTable' n = table "" (replicate n (AlignDefault, 0.0))
15+
16+tests :: [TestTree]
17+tests =
18+ [ "Single cell table" =:
19+ "|Test|" =?>
20+ simpleTable' 1 mempty [[plain "Test"]]
21+
22+ , "Multi cell table" =:
23+ "| One | Two |" =?>
24+ simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
25+
26+ , "Multi line table" =:
27+ T.unlines [ "| One |"
28+ , "| Two |"
29+ , "| Three |"
30+ ] =?>
31+ simpleTable' 1 mempty
32+ [ [ plain "One" ]
33+ , [ plain "Two" ]
34+ , [ plain "Three" ]
35+ ]
36+
37+ , "Empty table" =:
38+ "||" =?>
39+ simpleTable' 1 mempty [[mempty]]
40+
41+ , "Glider Table" =:
42+ T.unlines [ "| 1 | 0 | 0 |"
43+ , "| 0 | 1 | 1 |"
44+ , "| 1 | 1 | 0 |"
45+ ] =?>
46+ simpleTable' 3 mempty
47+ [ [ plain "1", plain "0", plain "0" ]
48+ , [ plain "0", plain "1", plain "1" ]
49+ , [ plain "1", plain "1", plain "0" ]
50+ ]
51+
52+ , "Table between Paragraphs" =:
53+ T.unlines [ "Before"
54+ , "| One | Two |"
55+ , "After"
56+ ] =?>
57+ mconcat [ para "Before"
58+ , simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
59+ , para "After"
60+ ]
61+
62+ , "Table with Header" =:
63+ T.unlines [ "| Species | Status |"
64+ , "|--------------+--------------|"
65+ , "| cervisiae | domesticated |"
66+ , "| paradoxus | wild |"
67+ ] =?>
68+ simpleTable [ plain "Species", plain "Status" ]
69+ [ [ plain "cervisiae", plain "domesticated" ]
70+ , [ plain "paradoxus", plain "wild" ]
71+ ]
72+
73+ , "Table with final hline" =:
74+ T.unlines [ "| cervisiae | domesticated |"
75+ , "| paradoxus | wild |"
76+ , "|--------------+--------------|"
77+ ] =?>
78+ simpleTable' 2 mempty
79+ [ [ plain "cervisiae", plain "domesticated" ]
80+ , [ plain "paradoxus", plain "wild" ]
81+ ]
82+
83+ , "Table in a box" =:
84+ T.unlines [ "|---------|---------|"
85+ , "| static | Haskell |"
86+ , "| dynamic | Lisp |"
87+ , "|---------+---------|"
88+ ] =?>
89+ simpleTable' 2 mempty
90+ [ [ plain "static", plain "Haskell" ]
91+ , [ plain "dynamic", plain "Lisp" ]
92+ ]
93+
94+ , "Table with empty cells" =:
95+ "|||c|" =?>
96+ simpleTable' 3 mempty [[mempty, mempty, plain "c"]]
97+
98+ , "Table with empty rows" =:
99+ T.unlines [ "| first |"
100+ , "| |"
101+ , "| third |"
102+ ] =?>
103+ simpleTable' 1 mempty [[plain "first"], [mempty], [plain "third"]]
104+
105+ , "Table with alignment row" =:
106+ T.unlines [ "| Numbers | Text | More |"
107+ , "| <c> | <r> | |"
108+ , "| 1 | One | foo |"
109+ , "| 2 | Two | bar |"
110+ ] =?>
111+ table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
112+ []
113+ [ [ plain "Numbers", plain "Text", plain "More" ]
114+ , [ plain "1" , plain "One" , plain "foo" ]
115+ , [ plain "2" , plain "Two" , plain "bar" ]
116+ ]
117+
118+ , "Pipe within text doesn't start a table" =:
119+ "Ceci n'est pas une | pipe " =?>
120+ para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
121+
122+ , "Missing pipe at end of row" =:
123+ "|incomplete-but-valid" =?>
124+ simpleTable' 1 mempty [ [ plain "incomplete-but-valid" ] ]
125+
126+ , "Table with differing row lengths" =:
127+ T.unlines [ "| Numbers | Text "
128+ , "|-"
129+ , "| <c> | <r> |"
130+ , "| 1 | One | foo |"
131+ , "| 2"
132+ ] =?>
133+ table "" (zip [AlignCenter, AlignRight] [0, 0])
134+ [ plain "Numbers", plain "Text" ]
135+ [ [ plain "1" , plain "One" , plain "foo" ]
136+ , [ plain "2" ]
137+ ]
138+
139+ , "Table with caption" =:
140+ T.unlines [ "#+CAPTION: Hitchhiker's Multiplication Table"
141+ , "| x | 6 |"
142+ , "| 9 | 42 |"
143+ ] =?>
144+ table "Hitchhiker's Multiplication Table"
145+ [(AlignDefault, 0), (AlignDefault, 0)]
146+ []
147+ [ [ plain "x", plain "6" ]
148+ , [ plain "9", plain "42" ]
149+ ]
150+ ]
test/Tests/Readers/Org/Directive.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Directive (tests) where
34
5+import Prelude
46import Data.Time (UTCTime (UTCTime), secondsToDiffTime)
57import Data.Time.Calendar (Day (ModifiedJulianDay))
68import Test.Tasty (TestTree, testGroup)
test/Tests/Readers/Org/Directive.hs.orignew file+199
@@ -0,0 +1,199 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Directive (tests) where
3+
4+import Data.Time (UTCTime (UTCTime), secondsToDiffTime)
5+import Data.Time.Calendar (Day (ModifiedJulianDay))
6+import Test.Tasty (TestTree, testGroup)
7+import Tests.Helpers ((=?>), ToString, purely, test)
8+import Tests.Readers.Org.Shared ((=:), tagSpan)
9+import Text.Pandoc
10+import Text.Pandoc.Builder
11+import qualified Data.ByteString as BS
12+import qualified Data.Text as T
13+
14+testWithFiles :: (ToString c)
15+ => [(FilePath, BS.ByteString)]
16+ -> String -- ^ name of test case
17+ -> (T.Text, c) -- ^ (input, expected value)
18+ -> TestTree
19+testWithFiles fileDefs = test (orgWithFiles fileDefs)
20+ where
21+orgWithFiles :: [(FilePath, BS.ByteString)] -> T.Text -> Pandoc
22+orgWithFiles fileDefs input =
23+ let readOrg' = readOrg def{ readerExtensions = getDefaultExtensions "org" }
24+ in flip purely input $ \inp -> do
25+ modifyPureState (\st -> st { stFiles = files fileDefs })
26+ readOrg' inp
27+
28+
29+files :: [(FilePath, BS.ByteString)] -> FileTree
30+files fileDefs =
31+ let dummyTime = UTCTime (ModifiedJulianDay 125) (secondsToDiffTime 0)
32+ in foldr (\(fp, bs) -> insertInFileTree fp (FileInfo dummyTime bs))
33+ mempty fileDefs
34+
35+tests :: [TestTree]
36+tests =
37+ [ testGroup "export options"
38+ [ "disable simple sub/superscript syntax" =:
39+ T.unlines [ "#+OPTIONS: ^:nil"
40+ , "a^b"
41+ ] =?>
42+ para "a^b"
43+
44+ , "directly select drawers to be exported" =:
45+ T.unlines [ "#+OPTIONS: d:(\"IMPORTANT\")"
46+ , ":IMPORTANT:"
47+ , "23"
48+ , ":END:"
49+ , ":BORING:"
50+ , "very boring"
51+ , ":END:"
52+ ] =?>
53+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "23")
54+
55+ , "exclude drawers from being exported" =:
56+ T.unlines [ "#+OPTIONS: d:(not \"BORING\")"
57+ , ":IMPORTANT:"
58+ , "5"
59+ , ":END:"
60+ , ":BORING:"
61+ , "very boring"
62+ , ":END:"
63+ ] =?>
64+ divWith (mempty, ["IMPORTANT", "drawer"], mempty) (para "5")
65+
66+ , "don't include archive trees" =:
67+ T.unlines [ "#+OPTIONS: arch:nil"
68+ , "* old :ARCHIVE:"
69+ ] =?>
70+ (mempty ::Blocks)
71+
72+ , "include complete archive trees" =:
73+ T.unlines [ "#+OPTIONS: arch:t"
74+ , "* old :ARCHIVE:"
75+ , " boring"
76+ ] =?>
77+ mconcat [ headerWith ("old", [], mempty) 1
78+ ("old" <> space <> tagSpan "ARCHIVE")
79+ , para "boring"
80+ ]
81+
82+ , "include archive tree header only" =:
83+ T.unlines [ "#+OPTIONS: arch:headline"
84+ , "* old :ARCHIVE:"
85+ , " boring"
86+ ] =?>
87+ headerWith ("old", [], mempty) 1 ("old" <> space <> tagSpan "ARCHIVE")
88+
89+ , "limit headline depth" =:
90+ T.unlines [ "#+OPTIONS: H:2"
91+ , "* top-level section"
92+ , "** subsection"
93+ , "*** list item 1"
94+ , "*** list item 2"
95+ ] =?>
96+ mconcat [ headerWith ("top-level-section", [], []) 1 "top-level section"
97+ , headerWith ("subsection", [], []) 2 "subsection"
98+ , orderedList [ para "list item 1", para "list item 2" ]
99+ ]
100+
101+ , "turn all headlines into lists" =:
102+ T.unlines [ "#+OPTIONS: H:0"
103+ , "first block"
104+ , "* top-level section 1"
105+ , "** subsection"
106+ , "* top-level section 2"
107+ ] =?>
108+ mconcat [ para "first block"
109+ , orderedList
110+ [ para "top-level section 1" <>
111+ orderedList [ para "subsection" ]
112+ , para "top-level section 2" ]
113+ ]
114+
115+ , "preserve linebreaks as hard breaks" =:
116+ T.unlines [ "#+OPTIONS: \\n:t"
117+ , "first"
118+ , "second"
119+ ] =?>
120+ para ("first" <> linebreak <> "second")
121+
122+ , "disable author export" =:
123+ T.unlines [ "#+OPTIONS: author:nil"
124+ , "#+AUTHOR: ShyGuy"
125+ ] =?>
126+ Pandoc nullMeta mempty
127+
128+ , "disable creator export" =:
129+ T.unlines [ "#+OPTIONS: creator:nil"
130+ , "#+creator: The Architect"
131+ ] =?>
132+ Pandoc nullMeta mempty
133+
134+ , "disable email export" =:
135+ T.unlines [ "#+OPTIONS: email:nil"
136+ , "#+email: no-mail-please@example.com"
137+ ] =?>
138+ Pandoc nullMeta mempty
139+
140+ , "disable inclusion of todo keywords" =:
141+ T.unlines [ "#+OPTIONS: todo:nil"
142+ , "** DONE todo export"
143+ ] =?>
144+ headerWith ("todo-export", [], []) 2 "todo export"
145+
146+ , "remove tags from headlines" =:
147+ T.unlines [ "#+OPTIONS: tags:nil"
148+ , "* Headline :hello:world:"
149+ ] =?>
150+ headerWith ("headline", [], mempty) 1 "Headline"
151+ ]
152+
153+ , testGroup "Include"
154+ [ testWithFiles [("./other.org", "content of other file\n")]
155+ "file inclusion"
156+ (T.unlines [ "#+include: \"other.org\"" ] =?>
157+ plain "content of other file")
158+
159+ , testWithFiles [("./world.org", "World\n\n")]
160+ "Included file belongs to item"
161+ (T.unlines [ "- Hello,\n #+include: \"world.org\"" ] =?>
162+ bulletList [para "Hello," <> para "World"])
163+
164+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
165+ "Default include preserves level"
166+ (T.unlines [ "#+include: \"level3.org\"" ] =?>
167+ headerWith ("level3", [], []) 3 "Level3")
168+
169+ , testWithFiles [("./level3.org", "*** Level3\n\n")]
170+ "Minlevel shifts level"
171+ (T.unlines [ "#+include: \"level3.org\" :minlevel 1" ] =?>
172+ headerWith ("level3", [], []) 1 "Level3")
173+
174+ , testWithFiles [("./src.hs", "putStrLn outString\n")]
175+ "Include file as source code snippet"
176+ (T.unlines [ "#+include: \"src.hs\" src haskell" ] =?>
177+ codeBlockWith ("", ["haskell"], []) "putStrLn outString\n")
178+
179+ , testWithFiles [("./export-latex.org", "\\emph{Hello}\n")]
180+ "Include file as export snippet"
181+ (T.unlines [ "#+include: \"export-latex.org\" export latex" ] =?>
182+ rawBlock "latex" "\\emph{Hello}\n")
183+
184+ , testWithFiles [("./subdir/foo-bar.latex", "foo\n"),
185+ ("./hello.lisp", "(print \"Hello!\")\n")
186+ ]
187+ "include directive is limited to one line"
188+ (T.unlines [ "#+INCLUDE: \"hello.lisp\" src lisp"
189+ , "#+include: \"subdir/foo-bar.latex\" export latex"
190+ , "bar"
191+ ] =?>
192+ mconcat
193+ [ codeBlockWith ("", ["lisp"], []) "(print \"Hello!\")\n"
194+ , rawBlock "latex" "foo\n"
195+ , para "bar"
196+ ]
197+ )
198+ ]
199+ ]
test/Tests/Readers/Org/Inline.hs+4−167
@@ -1,14 +1,16 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Inline (tests) where
34
5+import Prelude
46import Data.List (intersperse)
57import Test.Tasty (TestTree, testGroup)
68import Tests.Helpers ((=?>))
79import Tests.Readers.Org.Shared ((=:), spcSep)
8−import Text.Pandoc
910import Text.Pandoc.Builder
1011import Text.Pandoc.Shared (underlineSpan)
1112import qualified Data.Text as T
13+import qualified Tests.Readers.Org.Inline.Citation as Citation
1214import qualified Tests.Readers.Org.Inline.Note as Note
1315import qualified Tests.Readers.Org.Inline.Smart as Smart
1416
@@ -288,161 +290,6 @@ tests =
288290 )
289291 "echo $HOME")
290292
291− , "Citation" =:
292− "[@nonexistent]" =?>
293− let citation = Citation
294− { citationId = "nonexistent"
295− , citationPrefix = []
296− , citationSuffix = []
297− , citationMode = NormalCitation
298− , citationNoteNum = 0
299− , citationHash = 0}
300− in (para $ cite [citation] "[@nonexistent]")
301−
302− , "Citation containing text" =:
303− "[see @item1 p. 34-35]" =?>
304− let citation = Citation
305− { citationId = "item1"
306− , citationPrefix = [Str "see"]
307− , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
308− , citationMode = NormalCitation
309− , citationNoteNum = 0
310− , citationHash = 0}
311− in (para $ cite [citation] "[see @item1 p. 34-35]")
312−
313− , "Org-ref simple citation" =:
314− "cite:pandoc" =?>
315− let citation = Citation
316− { citationId = "pandoc"
317− , citationPrefix = mempty
318− , citationSuffix = mempty
319− , citationMode = AuthorInText
320− , citationNoteNum = 0
321− , citationHash = 0
322− }
323− in (para $ cite [citation] "cite:pandoc")
324−
325− , "Org-ref simple citation with underscores" =:
326− "cite:pandoc_org_ref" =?>
327− let citation = Citation
328− { citationId = "pandoc_org_ref"
329− , citationPrefix = mempty
330− , citationSuffix = mempty
331− , citationMode = AuthorInText
332− , citationNoteNum = 0
333− , citationHash = 0
334− }
335− in (para $ cite [citation] "cite:pandoc_org_ref")
336−
337− , "Org-ref simple citation succeeded by comma" =:
338− "cite:pandoc," =?>
339− let citation = Citation
340− { citationId = "pandoc"
341− , citationPrefix = mempty
342− , citationSuffix = mempty
343− , citationMode = AuthorInText
344− , citationNoteNum = 0
345− , citationHash = 0
346− }
347− in (para $ cite [citation] "cite:pandoc" <> str ",")
348−
349− , "Org-ref simple citation succeeded by dot" =:
350− "cite:pandoc." =?>
351− let citation = Citation
352− { citationId = "pandoc"
353− , citationPrefix = mempty
354− , citationSuffix = mempty
355− , citationMode = AuthorInText
356− , citationNoteNum = 0
357− , citationHash = 0
358− }
359− in (para $ cite [citation] "cite:pandoc" <> str ".")
360−
361− , "Org-ref simple citation succeeded by colon" =:
362− "cite:pandoc:" =?>
363− let citation = Citation
364− { citationId = "pandoc"
365− , citationPrefix = mempty
366− , citationSuffix = mempty
367− , citationMode = AuthorInText
368− , citationNoteNum = 0
369− , citationHash = 0
370− }
371− in (para $ cite [citation] "cite:pandoc" <> str ":")
372−
373− , "Org-ref simple citep citation" =:
374− "citep:pandoc" =?>
375− let citation = Citation
376− { citationId = "pandoc"
377− , citationPrefix = mempty
378− , citationSuffix = mempty
379− , citationMode = NormalCitation
380− , citationNoteNum = 0
381− , citationHash = 0
382− }
383− in (para $ cite [citation] "citep:pandoc")
384−
385− , "Org-ref extended citation" =:
386− "[[citep:Dominik201408][See page 20::, for example]]" =?>
387− let citation = Citation
388− { citationId = "Dominik201408"
389− , citationPrefix = toList "See page 20"
390− , citationSuffix = toList ", for example"
391− , citationMode = NormalCitation
392− , citationNoteNum = 0
393− , citationHash = 0
394− }
395− in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
396−
397− , testGroup "Berkeley-style citations" $
398− let pandocCite = Citation
399− { citationId = "Pandoc"
400− , citationPrefix = mempty
401− , citationSuffix = mempty
402− , citationMode = NormalCitation
403− , citationNoteNum = 0
404− , citationHash = 0
405− }
406− pandocInText = pandocCite { citationMode = AuthorInText }
407− dominikCite = Citation
408− { citationId = "Dominik201408"
409− , citationPrefix = mempty
410− , citationSuffix = mempty
411− , citationMode = NormalCitation
412− , citationNoteNum = 0
413− , citationHash = 0
414− }
415− dominikInText = dominikCite { citationMode = AuthorInText }
416− in [
417− "Berkeley-style in-text citation" =:
418− "See @Dominik201408." =?>
419− para ("See "
420− <> cite [dominikInText] "@Dominik201408"
421− <> ".")
422−
423− , "Berkeley-style parenthetical citation list" =:
424− "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
425− let pandocCite' = pandocCite {
426− citationPrefix = toList "also"
427− , citationSuffix = toList "and others"
428− }
429− dominikCite' = dominikCite {
430− citationPrefix = toList "see"
431− }
432− in (para $ cite [dominikCite', pandocCite'] "")
433−
434− , "Berkeley-style plain citation list" =:
435− "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
436− let pandocCite' = pandocInText {
437− citationPrefix = toList "and"
438− }
439− in (para $ "See "
440− <> cite [dominikInText] ""
441− <> "," <> space
442− <> cite [pandocCite'] ""
443− <> "," <> space <> "and others")
444− ]
445−
446293 , "Inline LaTeX symbol" =:
447294 "\\dots" =?>
448295 para "…"
@@ -483,17 +330,6 @@ tests =
483330 "\\ForAll \\Auml" =?>
484331 para "∀ Ä"
485332
486− , "LaTeX citation" =:
487− "\\cite{Coffee}" =?>
488− let citation = Citation
489− { citationId = "Coffee"
490− , citationPrefix = []
491− , citationSuffix = []
492− , citationMode = NormalCitation
493− , citationNoteNum = 0
494− , citationHash = 0}
495− in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
496−
497333 , "Macro" =:
498334 T.unlines [ "#+MACRO: HELLO /Hello, $1/"
499335 , "{{{HELLO(World)}}}"
@@ -512,6 +348,7 @@ tests =
512348 ] =?>
513349 para "Foo Bar"
514350
351+ , testGroup "Citations" Citation.tests
515352 , testGroup "Footnotes" Note.tests
516353 , testGroup "Smart punctuation" Smart.tests
517354 ]
test/Tests/Readers/Org/Inline.hs.orignew file+352
@@ -0,0 +1,352 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Inline (tests) where
3+
4+import Data.List (intersperse)
5+import Test.Tasty (TestTree, testGroup)
6+import Tests.Helpers ((=?>))
7+import Tests.Readers.Org.Shared ((=:), spcSep)
8+import Text.Pandoc.Builder
9+import Text.Pandoc.Shared (underlineSpan)
10+import qualified Data.Text as T
11+import qualified Tests.Readers.Org.Inline.Citation as Citation
12+import qualified Tests.Readers.Org.Inline.Note as Note
13+import qualified Tests.Readers.Org.Inline.Smart as Smart
14+
15+tests :: [TestTree]
16+tests =
17+ [ "Plain String" =:
18+ "Hello, World" =?>
19+ para (spcSep [ "Hello,", "World" ])
20+
21+ , "Emphasis" =:
22+ "/Planet Punk/" =?>
23+ para (emph . spcSep $ ["Planet", "Punk"])
24+
25+ , "Strong" =:
26+ "*Cider*" =?>
27+ para (strong "Cider")
28+
29+ , "Strong Emphasis" =:
30+ "/*strength*/" =?>
31+ para (emph . strong $ "strength")
32+
33+ , "Emphasized Strong preceded by space" =:
34+ " */super/*" =?>
35+ para (strong . emph $ "super")
36+
37+ , "Underline" =:
38+ "_underline_" =?>
39+ para (underlineSpan "underline")
40+
41+ , "Strikeout" =:
42+ "+Kill Bill+" =?>
43+ para (strikeout . spcSep $ [ "Kill", "Bill" ])
44+
45+ , "Verbatim" =:
46+ "=Robot.rock()=" =?>
47+ para (code "Robot.rock()")
48+
49+ , "Code" =:
50+ "~word for word~" =?>
51+ para (code "word for word")
52+
53+ , "Math $..$" =:
54+ "$E=mc^2$" =?>
55+ para (math "E=mc^2")
56+
57+ , "Math $$..$$" =:
58+ "$$E=mc^2$$" =?>
59+ para (displayMath "E=mc^2")
60+
61+ , "Math \\[..\\]" =:
62+ "\\[E=ℎν\\]" =?>
63+ para (displayMath "E=ℎν")
64+
65+ , "Math \\(..\\)" =:
66+ "\\(σ_x σ_p ≥ \\frac{ℏ}{2}\\)" =?>
67+ para (math "σ_x σ_p ≥ \\frac{ℏ}{2}")
68+
69+ , "Symbol" =:
70+ "A * symbol" =?>
71+ para (str "A" <> space <> str "*" <> space <> "symbol")
72+
73+ , "Superscript simple expression" =:
74+ "2^-λ" =?>
75+ para (str "2" <> superscript "-λ")
76+
77+ , "Superscript multi char" =:
78+ "2^{n-1}" =?>
79+ para (str "2" <> superscript "n-1")
80+
81+ , "Subscript simple expression" =:
82+ "a_n" =?>
83+ para (str "a" <> subscript "n")
84+
85+ , "Subscript multi char" =:
86+ "a_{n+1}" =?>
87+ para (str "a" <> subscript "n+1")
88+
89+ , "Linebreak" =:
90+ "line \\\\ \nbreak" =?>
91+ para ("line" <> linebreak <> "break")
92+
93+ , "Inline note" =:
94+ "[fn::Schreib mir eine E-Mail]" =?>
95+ para (note $ para "Schreib mir eine E-Mail")
96+
97+ , "Markup-chars not occuring on word break are symbols" =:
98+ T.unlines [ "this+that+ +so+on"
99+ , "seven*eight* nine*"
100+ , "+not+funny+"
101+ ] =?>
102+ para ("this+that+ +so+on" <> softbreak <>
103+ "seven*eight* nine*" <> softbreak <>
104+ strikeout "not+funny")
105+
106+ , "No empty markup" =:
107+ "// ** __ <> == ~~ $$" =?>
108+ para (spcSep [ "//", "**", "__", "<>", "==", "~~", "$$" ])
109+
110+ , "Adherence to Org's rules for markup borders" =:
111+ "/t/& a/ / ./r/ (*l*) /e/! /b/." =?>
112+ para (spcSep [ emph $ "t/&" <> space <> "a"
113+ , "/"
114+ , "./r/"
115+ , "(" <> strong "l" <> ")"
116+ , emph "e" <> "!"
117+ , emph "b" <> "."
118+ ])
119+
120+ , "Quotes are allowed border chars" =:
121+ "/'yep/ *sure\"*" =?>
122+ para (emph "'yep" <> space <> strong "sure\"")
123+
124+ , "Spaces are forbidden border chars" =:
125+ "/nada /" =?>
126+ para "/nada /"
127+
128+ , "Markup should work properly after a blank line" =:
129+ T.unlines ["foo", "", "/bar/"] =?>
130+ para (text "foo") <>
131+ para (emph $ text "bar")
132+
133+ , "Inline math must stay within three lines" =:
134+ T.unlines [ "$a", "b", "c$", "$d", "e", "f", "g$" ] =?>
135+ para (math "a\nb\nc" <> softbreak <>
136+ "$d" <> softbreak <> "e" <> softbreak <>
137+ "f" <> softbreak <> "g$")
138+
139+ , "Single-character math" =:
140+ "$a$ $b$! $c$?" =?>
141+ para (spcSep [ math "a"
142+ , "$b$!"
143+ , math "c" <> "?"
144+ ])
145+
146+ , "Markup may not span more than two lines" =:
147+ "/this *is +totally\nnice+ not*\nemph/" =?>
148+ para ("/this" <> space <>
149+ strong ("is" <> space <>
150+ strikeout ("totally" <>
151+ softbreak <> "nice") <>
152+ space <> "not") <>
153+ softbreak <> "emph/")
154+
155+ , "Sub- and superscript expressions" =:
156+ T.unlines [ "a_(a(b)(c)d)"
157+ , "e^(f(g)h)"
158+ , "i_(jk)l)"
159+ , "m^()n"
160+ , "o_{p{q{}r}}"
161+ , "s^{t{u}v}"
162+ , "w_{xy}z}"
163+ , "1^{}2"
164+ , "3_{{}}"
165+ , "4^(a(*b(c*)d))"
166+ ] =?>
167+ para (mconcat $ intersperse softbreak
168+ [ "a" <> subscript "(a(b)(c)d)"
169+ , "e" <> superscript "(f(g)h)"
170+ , "i" <> subscript "(jk)" <> "l)"
171+ , "m" <> superscript "()" <> "n"
172+ , "o" <> subscript "p{q{}r}"
173+ , "s" <> superscript "t{u}v"
174+ , "w" <> subscript "xy" <> "z}"
175+ , "1" <> superscript "" <> "2"
176+ , "3" <> subscript "{}"
177+ , "4" <> superscript ("(a(" <> strong "b(c" <> ")d))")
178+ ])
179+ , "Verbatim text can contain equal signes (=)" =:
180+ "=is_subst = True=" =?>
181+ para (code "is_subst = True")
182+
183+ , testGroup "Images"
184+ [ "Image" =:
185+ "[[./sunset.jpg]]" =?>
186+ para (image "./sunset.jpg" "" "")
187+
188+ , "Image with explicit file: prefix" =:
189+ "[[file:sunrise.jpg]]" =?>
190+ para (image "sunrise.jpg" "" "")
191+
192+ , "Multiple images within a paragraph" =:
193+ T.unlines [ "[[file:sunrise.jpg]]"
194+ , "[[file:sunset.jpg]]"
195+ ] =?>
196+ para ((image "sunrise.jpg" "" "")
197+ <> softbreak
198+ <> (image "sunset.jpg" "" ""))
199+
200+ , "Image with html attributes" =:
201+ T.unlines [ "#+ATTR_HTML: :width 50%"
202+ , "[[file:guinea-pig.gif]]"
203+ ] =?>
204+ para (imageWith ("", [], [("width", "50%")]) "guinea-pig.gif" "" "")
205+ ]
206+
207+ , "Explicit link" =:
208+ "[[http://zeitlens.com/][pseudo-random /nonsense/]]" =?>
209+ para (link "http://zeitlens.com/" ""
210+ ("pseudo-random" <> space <> emph "nonsense"))
211+
212+ , "Self-link" =:
213+ "[[http://zeitlens.com/]]" =?>
214+ para (link "http://zeitlens.com/" "" "http://zeitlens.com/")
215+
216+ , "Absolute file link" =:
217+ "[[/url][hi]]" =?>
218+ para (link "file:///url" "" "hi")
219+
220+ , "Link to file in parent directory" =:
221+ "[[../file.txt][moin]]" =?>
222+ para (link "../file.txt" "" "moin")
223+
224+ , "Empty link (for gitit interop)" =:
225+ "[[][New Link]]" =?>
226+ para (link "" "" "New Link")
227+
228+ , "Image link" =:
229+ "[[sunset.png][file:dusk.svg]]" =?>
230+ para (link "sunset.png" "" (image "dusk.svg" "" ""))
231+
232+ , "Image link with non-image target" =:
233+ "[[http://example.com][./logo.png]]" =?>
234+ para (link "http://example.com" "" (image "./logo.png" "" ""))
235+
236+ , "Plain link" =:
237+ "Posts on http://zeitlens.com/ can be funny at times." =?>
238+ para (spcSep [ "Posts", "on"
239+ , link "http://zeitlens.com/" "" "http://zeitlens.com/"
240+ , "can", "be", "funny", "at", "times."
241+ ])
242+
243+ , "Angle link" =:
244+ "Look at <http://moltkeplatz.de> for fnords." =?>
245+ para (spcSep [ "Look", "at"
246+ , link "http://moltkeplatz.de" "" "http://moltkeplatz.de"
247+ , "for", "fnords."
248+ ])
249+
250+ , "Absolute file link" =:
251+ "[[file:///etc/passwd][passwd]]" =?>
252+ para (link "file:///etc/passwd" "" "passwd")
253+
254+ , "File link" =:
255+ "[[file:target][title]]" =?>
256+ para (link "target" "" "title")
257+
258+ , "Anchor" =:
259+ "<<anchor>> Link here later." =?>
260+ para (spanWith ("anchor", [], []) mempty <>
261+ "Link" <> space <> "here" <> space <> "later.")
262+
263+ , "Inline code block" =:
264+ "src_emacs-lisp{(message \"Hello\")}" =?>
265+ para (codeWith ( ""
266+ , [ "commonlisp" ]
267+ , [ ("org-language", "emacs-lisp") ])
268+ "(message \"Hello\")")
269+
270+ , "Inline code block with arguments" =:
271+ "src_sh[:export both :results output]{echo 'Hello, World'}" =?>
272+ para (codeWith ( ""
273+ , [ "bash" ]
274+ , [ ("org-language", "sh")
275+ , ("export", "both")
276+ , ("results", "output")
277+ ]
278+ )
279+ "echo 'Hello, World'")
280+
281+ , "Inline code block with toggle" =:
282+ "src_sh[:toggle]{echo $HOME}" =?>
283+ para (codeWith ( ""
284+ , [ "bash" ]
285+ , [ ("org-language", "sh")
286+ , ("toggle", "yes")
287+ ]
288+ )
289+ "echo $HOME")
290+
291+ , "Inline LaTeX symbol" =:
292+ "\\dots" =?>
293+ para "…"
294+
295+ , "Inline LaTeX command" =:
296+ "\\textit{Emphasised}" =?>
297+ para (emph "Emphasised")
298+
299+ , "Inline LaTeX command with spaces" =:
300+ "\\emph{Emphasis mine}" =?>
301+ para (emph "Emphasis mine")
302+
303+ , "Inline LaTeX math symbol" =:
304+ "\\tau" =?>
305+ para (emph "τ")
306+
307+ , "Unknown inline LaTeX command" =:
308+ "\\notacommand{foo}" =?>
309+ para (rawInline "latex" "\\notacommand{foo}")
310+
311+ , "Export snippet" =:
312+ "@@html:<kbd>M-x org-agenda</kbd>@@" =?>
313+ para (rawInline "html" "<kbd>M-x org-agenda</kbd>")
314+
315+ , "MathML symbol in LaTeX-style" =:
316+ "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: '\\nbsp')." =?>
317+ para "There is a hackerspace in Lübeck, Germany, called nbsp (unicode symbol: ' ')."
318+
319+ , "MathML symbol in LaTeX-style, including braces" =:
320+ "\\Aacute{}stor" =?>
321+ para "Ástor"
322+
323+ , "MathML copy sign" =:
324+ "\\copy" =?>
325+ para "©"
326+
327+ , "MathML symbols, space separated" =:
328+ "\\ForAll \\Auml" =?>
329+ para "∀ Ä"
330+
331+ , "Macro" =:
332+ T.unlines [ "#+MACRO: HELLO /Hello, $1/"
333+ , "{{{HELLO(World)}}}"
334+ ] =?>
335+ para (emph "Hello, World")
336+
337+ , "Macro repeting its argument" =:
338+ T.unlines [ "#+MACRO: HELLO $1$1"
339+ , "{{{HELLO(moin)}}}"
340+ ] =?>
341+ para "moinmoin"
342+
343+ , "Macro called with too few arguments" =:
344+ T.unlines [ "#+MACRO: HELLO Foo $1 $2 Bar"
345+ , "{{{HELLO()}}}"
346+ ] =?>
347+ para "Foo Bar"
348+
349+ , testGroup "Citations" Citation.tests
350+ , testGroup "Footnotes" Note.tests
351+ , testGroup "Smart punctuation" Smart.tests
352+ ]
test/Tests/Readers/Org/Inline/Citation.hsnew file+181
@@ -0,0 +1,181 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+module Tests.Readers.Org.Inline.Citation (tests) where
4+
5+import Prelude
6+import Test.Tasty (TestTree, testGroup)
7+import Tests.Helpers ((=?>))
8+import Tests.Readers.Org.Shared ((=:))
9+import Text.Pandoc.Builder
10+
11+tests :: [TestTree]
12+tests =
13+ [ testGroup "Markdown-style citations"
14+ [ "Citation" =:
15+ "[@nonexistent]" =?>
16+ let citation = Citation
17+ { citationId = "nonexistent"
18+ , citationPrefix = []
19+ , citationSuffix = []
20+ , citationMode = NormalCitation
21+ , citationNoteNum = 0
22+ , citationHash = 0}
23+ in (para $ cite [citation] "[@nonexistent]")
24+
25+ , "Citation containing text" =:
26+ "[see @item1 p. 34-35]" =?>
27+ let citation = Citation
28+ { citationId = "item1"
29+ , citationPrefix = [Str "see"]
30+ , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
31+ , citationMode = NormalCitation
32+ , citationNoteNum = 0
33+ , citationHash = 0}
34+ in (para $ cite [citation] "[see @item1 p. 34-35]")
35+ ]
36+
37+ , testGroup "org-ref citations"
38+ [ "simple citation" =:
39+ "cite:pandoc" =?>
40+ let citation = Citation
41+ { citationId = "pandoc"
42+ , citationPrefix = mempty
43+ , citationSuffix = mempty
44+ , citationMode = AuthorInText
45+ , citationNoteNum = 0
46+ , citationHash = 0
47+ }
48+ in (para $ cite [citation] "cite:pandoc")
49+
50+ , "simple citation with underscores" =:
51+ "cite:pandoc_org_ref" =?>
52+ let citation = Citation
53+ { citationId = "pandoc_org_ref"
54+ , citationPrefix = mempty
55+ , citationSuffix = mempty
56+ , citationMode = AuthorInText
57+ , citationNoteNum = 0
58+ , citationHash = 0
59+ }
60+ in (para $ cite [citation] "cite:pandoc_org_ref")
61+
62+ , "simple citation succeeded by comma" =:
63+ "cite:pandoc," =?>
64+ let citation = Citation
65+ { citationId = "pandoc"
66+ , citationPrefix = mempty
67+ , citationSuffix = mempty
68+ , citationMode = AuthorInText
69+ , citationNoteNum = 0
70+ , citationHash = 0
71+ }
72+ in (para $ cite [citation] "cite:pandoc" <> str ",")
73+
74+ , "simple citation succeeded by dot" =:
75+ "cite:pandoc." =?>
76+ let citation = Citation
77+ { citationId = "pandoc"
78+ , citationPrefix = mempty
79+ , citationSuffix = mempty
80+ , citationMode = AuthorInText
81+ , citationNoteNum = 0
82+ , citationHash = 0
83+ }
84+ in (para $ cite [citation] "cite:pandoc" <> str ".")
85+
86+ , "simple citation succeeded by colon" =:
87+ "cite:pandoc:" =?>
88+ let citation = Citation
89+ { citationId = "pandoc"
90+ , citationPrefix = mempty
91+ , citationSuffix = mempty
92+ , citationMode = AuthorInText
93+ , citationNoteNum = 0
94+ , citationHash = 0
95+ }
96+ in (para $ cite [citation] "cite:pandoc" <> str ":")
97+
98+ , "simple citep citation" =:
99+ "citep:pandoc" =?>
100+ let citation = Citation
101+ { citationId = "pandoc"
102+ , citationPrefix = mempty
103+ , citationSuffix = mempty
104+ , citationMode = NormalCitation
105+ , citationNoteNum = 0
106+ , citationHash = 0
107+ }
108+ in (para $ cite [citation] "citep:pandoc")
109+
110+ , "extended citation" =:
111+ "[[citep:Dominik201408][See page 20::, for example]]" =?>
112+ let citation = Citation
113+ { citationId = "Dominik201408"
114+ , citationPrefix = toList "See page 20"
115+ , citationSuffix = toList ", for example"
116+ , citationMode = NormalCitation
117+ , citationNoteNum = 0
118+ , citationHash = 0
119+ }
120+ in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
121+ ]
122+
123+ , testGroup "Berkeley-style citations" $
124+ let pandocCite = Citation
125+ { citationId = "Pandoc"
126+ , citationPrefix = mempty
127+ , citationSuffix = mempty
128+ , citationMode = NormalCitation
129+ , citationNoteNum = 0
130+ , citationHash = 0
131+ }
132+ pandocInText = pandocCite { citationMode = AuthorInText }
133+ dominikCite = Citation
134+ { citationId = "Dominik201408"
135+ , citationPrefix = mempty
136+ , citationSuffix = mempty
137+ , citationMode = NormalCitation
138+ , citationNoteNum = 0
139+ , citationHash = 0
140+ }
141+ dominikInText = dominikCite { citationMode = AuthorInText }
142+ in
143+ [ "Berkeley-style in-text citation" =:
144+ "See @Dominik201408." =?>
145+ para ("See "
146+ <> cite [dominikInText] "@Dominik201408"
147+ <> ".")
148+
149+ , "Berkeley-style parenthetical citation list" =:
150+ "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
151+ let pandocCite' = pandocCite {
152+ citationPrefix = toList "also"
153+ , citationSuffix = toList "and others"
154+ }
155+ dominikCite' = dominikCite {
156+ citationPrefix = toList "see"
157+ }
158+ in (para $ cite [dominikCite', pandocCite'] "")
159+
160+ , "Berkeley-style plain citation list" =:
161+ "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
162+ let pandocCite' = pandocInText { citationPrefix = toList "and" }
163+ in (para $ "See "
164+ <> cite [dominikInText] ""
165+ <> "," <> space
166+ <> cite [pandocCite'] ""
167+ <> "," <> space <> "and others")
168+ ]
169+
170+ , "LaTeX citation" =:
171+ "\\cite{Coffee}" =?>
172+ let citation = Citation
173+ { citationId = "Coffee"
174+ , citationPrefix = []
175+ , citationSuffix = []
176+ , citationMode = NormalCitation
177+ , citationNoteNum = 0
178+ , citationHash = 0}
179+ in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
180+
181+ ]
test/Tests/Readers/Org/Inline/Citation.hs.orignew file+179
@@ -0,0 +1,179 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Inline.Citation (tests) where
3+
4+import Test.Tasty (TestTree, testGroup)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:))
7+import Text.Pandoc.Builder
8+
9+tests :: [TestTree]
10+tests =
11+ [ testGroup "Markdown-style citations"
12+ [ "Citation" =:
13+ "[@nonexistent]" =?>
14+ let citation = Citation
15+ { citationId = "nonexistent"
16+ , citationPrefix = []
17+ , citationSuffix = []
18+ , citationMode = NormalCitation
19+ , citationNoteNum = 0
20+ , citationHash = 0}
21+ in (para $ cite [citation] "[@nonexistent]")
22+
23+ , "Citation containing text" =:
24+ "[see @item1 p. 34-35]" =?>
25+ let citation = Citation
26+ { citationId = "item1"
27+ , citationPrefix = [Str "see"]
28+ , citationSuffix = [Space ,Str "p.",Space,Str "34-35"]
29+ , citationMode = NormalCitation
30+ , citationNoteNum = 0
31+ , citationHash = 0}
32+ in (para $ cite [citation] "[see @item1 p. 34-35]")
33+ ]
34+
35+ , testGroup "org-ref citations"
36+ [ "simple citation" =:
37+ "cite:pandoc" =?>
38+ let citation = Citation
39+ { citationId = "pandoc"
40+ , citationPrefix = mempty
41+ , citationSuffix = mempty
42+ , citationMode = AuthorInText
43+ , citationNoteNum = 0
44+ , citationHash = 0
45+ }
46+ in (para $ cite [citation] "cite:pandoc")
47+
48+ , "simple citation with underscores" =:
49+ "cite:pandoc_org_ref" =?>
50+ let citation = Citation
51+ { citationId = "pandoc_org_ref"
52+ , citationPrefix = mempty
53+ , citationSuffix = mempty
54+ , citationMode = AuthorInText
55+ , citationNoteNum = 0
56+ , citationHash = 0
57+ }
58+ in (para $ cite [citation] "cite:pandoc_org_ref")
59+
60+ , "simple citation succeeded by comma" =:
61+ "cite:pandoc," =?>
62+ let citation = Citation
63+ { citationId = "pandoc"
64+ , citationPrefix = mempty
65+ , citationSuffix = mempty
66+ , citationMode = AuthorInText
67+ , citationNoteNum = 0
68+ , citationHash = 0
69+ }
70+ in (para $ cite [citation] "cite:pandoc" <> str ",")
71+
72+ , "simple citation succeeded by dot" =:
73+ "cite:pandoc." =?>
74+ let citation = Citation
75+ { citationId = "pandoc"
76+ , citationPrefix = mempty
77+ , citationSuffix = mempty
78+ , citationMode = AuthorInText
79+ , citationNoteNum = 0
80+ , citationHash = 0
81+ }
82+ in (para $ cite [citation] "cite:pandoc" <> str ".")
83+
84+ , "simple citation succeeded by colon" =:
85+ "cite:pandoc:" =?>
86+ let citation = Citation
87+ { citationId = "pandoc"
88+ , citationPrefix = mempty
89+ , citationSuffix = mempty
90+ , citationMode = AuthorInText
91+ , citationNoteNum = 0
92+ , citationHash = 0
93+ }
94+ in (para $ cite [citation] "cite:pandoc" <> str ":")
95+
96+ , "simple citep citation" =:
97+ "citep:pandoc" =?>
98+ let citation = Citation
99+ { citationId = "pandoc"
100+ , citationPrefix = mempty
101+ , citationSuffix = mempty
102+ , citationMode = NormalCitation
103+ , citationNoteNum = 0
104+ , citationHash = 0
105+ }
106+ in (para $ cite [citation] "citep:pandoc")
107+
108+ , "extended citation" =:
109+ "[[citep:Dominik201408][See page 20::, for example]]" =?>
110+ let citation = Citation
111+ { citationId = "Dominik201408"
112+ , citationPrefix = toList "See page 20"
113+ , citationSuffix = toList ", for example"
114+ , citationMode = NormalCitation
115+ , citationNoteNum = 0
116+ , citationHash = 0
117+ }
118+ in (para $ cite [citation] "[[citep:Dominik201408][See page 20::, for example]]")
119+ ]
120+
121+ , testGroup "Berkeley-style citations" $
122+ let pandocCite = Citation
123+ { citationId = "Pandoc"
124+ , citationPrefix = mempty
125+ , citationSuffix = mempty
126+ , citationMode = NormalCitation
127+ , citationNoteNum = 0
128+ , citationHash = 0
129+ }
130+ pandocInText = pandocCite { citationMode = AuthorInText }
131+ dominikCite = Citation
132+ { citationId = "Dominik201408"
133+ , citationPrefix = mempty
134+ , citationSuffix = mempty
135+ , citationMode = NormalCitation
136+ , citationNoteNum = 0
137+ , citationHash = 0
138+ }
139+ dominikInText = dominikCite { citationMode = AuthorInText }
140+ in
141+ [ "Berkeley-style in-text citation" =:
142+ "See @Dominik201408." =?>
143+ para ("See "
144+ <> cite [dominikInText] "@Dominik201408"
145+ <> ".")
146+
147+ , "Berkeley-style parenthetical citation list" =:
148+ "[(cite): see; @Dominik201408;also @Pandoc; and others]" =?>
149+ let pandocCite' = pandocCite {
150+ citationPrefix = toList "also"
151+ , citationSuffix = toList "and others"
152+ }
153+ dominikCite' = dominikCite {
154+ citationPrefix = toList "see"
155+ }
156+ in (para $ cite [dominikCite', pandocCite'] "")
157+
158+ , "Berkeley-style plain citation list" =:
159+ "[cite: See; @Dominik201408; and @Pandoc; and others]" =?>
160+ let pandocCite' = pandocInText { citationPrefix = toList "and" }
161+ in (para $ "See "
162+ <> cite [dominikInText] ""
163+ <> "," <> space
164+ <> cite [pandocCite'] ""
165+ <> "," <> space <> "and others")
166+ ]
167+
168+ , "LaTeX citation" =:
169+ "\\cite{Coffee}" =?>
170+ let citation = Citation
171+ { citationId = "Coffee"
172+ , citationPrefix = []
173+ , citationSuffix = []
174+ , citationMode = NormalCitation
175+ , citationNoteNum = 0
176+ , citationHash = 0}
177+ in (para . cite [citation] $ rawInline "latex" "\\cite{Coffee}")
178+
179+ ]
test/Tests/Readers/Org/Inline/Note.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Inline.Note (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:))
test/Tests/Readers/Org/Inline/Note.hs.orignew file+86
@@ -0,0 +1,86 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Inline.Note (tests) where
3+
4+import Test.Tasty (TestTree)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:))
7+import Text.Pandoc.Builder
8+import qualified Data.Text as T
9+
10+tests :: [TestTree]
11+tests =
12+ [ "Footnote" =:
13+ T.unlines [ "A footnote[1]"
14+ , ""
15+ , "[1] First paragraph"
16+ , ""
17+ , "second paragraph"
18+ ] =?>
19+ para (mconcat
20+ [ "A", space, "footnote"
21+ , note $ mconcat [ para ("First" <> space <> "paragraph")
22+ , para ("second" <> space <> "paragraph")
23+ ]
24+ ])
25+
26+ , "Two footnotes" =:
27+ T.unlines [ "Footnotes[fn:1][fn:2]"
28+ , ""
29+ , "[fn:1] First note."
30+ , ""
31+ , "[fn:2] Second note."
32+ ] =?>
33+ para (mconcat
34+ [ "Footnotes"
35+ , note $ para ("First" <> space <> "note.")
36+ , note $ para ("Second" <> space <> "note.")
37+ ])
38+
39+ , "Emphasized text before footnote" =:
40+ T.unlines [ "/text/[fn:1]"
41+ , ""
42+ , "[fn:1] unicorn"
43+ ] =?>
44+ para (mconcat
45+ [ emph "text"
46+ , note . para $ "unicorn"
47+ ])
48+
49+ , "Footnote that starts with emphasized text" =:
50+ T.unlines [ "text[fn:1]"
51+ , ""
52+ , "[fn:1] /emphasized/"
53+ ] =?>
54+ para (mconcat
55+ [ "text"
56+ , note . para $ emph "emphasized"
57+ ])
58+
59+ , "Footnote followed by header" =:
60+ T.unlines [ "Another note[fn:yay]"
61+ , ""
62+ , "[fn:yay] This is great!"
63+ , ""
64+ , "** Headline"
65+ ] =?>
66+ mconcat
67+ [ para (mconcat
68+ [ "Another", space, "note"
69+ , note $ para ("This" <> space <> "is" <> space <> "great!")
70+ ])
71+ , headerWith ("headline", [], []) 2 "Headline"
72+ ]
73+
74+ , "Footnote followed by two blank lines" =:
75+ T.unlines [ "footnote[fn:blanklines]"
76+ , ""
77+ , "[fn:blanklines] followed by blank lines"
78+ , ""
79+ , ""
80+ , "next"
81+ ] =?>
82+ mconcat
83+ [ para ("footnote" <> note (para "followed by blank lines"))
84+ , para "next"
85+ ]
86+ ]
test/Tests/Readers/Org/Inline/Smart.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Inline.Smart (tests) where
34
5+import Prelude
46import Data.Text (Text)
57import Test.Tasty (TestTree)
68import Tests.Helpers ((=?>), purely, test)
test/Tests/Readers/Org/Inline/Smart.hs.orignew file+46
@@ -0,0 +1,46 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Inline.Smart (tests) where
3+
4+import Data.Text (Text)
5+import Test.Tasty (TestTree)
6+import Tests.Helpers ((=?>), purely, test)
7+import Text.Pandoc (ReaderOptions (readerExtensions),
8+ Extension (Ext_smart), def, enableExtension,
9+ getDefaultExtensions, readOrg)
10+import Text.Pandoc.Builder
11+
12+orgSmart :: Text -> Pandoc
13+orgSmart = purely $
14+ let extensionsSmart = enableExtension Ext_smart (getDefaultExtensions "org")
15+ in readOrg def{ readerExtensions = extensionsSmart }
16+
17+tests :: [TestTree]
18+tests =
19+ [ test orgSmart "quote before ellipses"
20+ ("'...hi'"
21+ =?> para (singleQuoted "…hi"))
22+
23+ , test orgSmart "apostrophe before emph"
24+ ("D'oh! A l'/aide/!"
25+ =?> para ("D’oh! A l’" <> emph "aide" <> "!"))
26+
27+ , test orgSmart "apostrophe in French"
28+ ("À l'arrivée de la guerre, le thème de l'«impossibilité du socialisme»"
29+ =?> para "À l’arrivée de la guerre, le thème de l’«impossibilité du socialisme»")
30+
31+ , test orgSmart "Quotes cannot occur at the end of emphasized text"
32+ ("/say \"yes\"/" =?>
33+ para ("/say" <> space <> doubleQuoted "yes" <> "/"))
34+
35+ , test orgSmart "Dashes are allowed at the borders of emphasis'"
36+ ("/foo---/" =?>
37+ para (emph "foo—"))
38+
39+ , test orgSmart "Single quotes can be followed by emphasized text"
40+ ("Singles on the '/meat market/'" =?>
41+ para ("Singles on the " <> singleQuoted (emph "meat market")))
42+
43+ , test orgSmart "Double quotes can be followed by emphasized text"
44+ ("Double income, no kids: \"/DINK/\"" =?>
45+ para ("Double income, no kids: " <> doubleQuoted (emph "DINK")))
46+ ]
test/Tests/Readers/Org/Meta.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Org.Meta (tests) where
34
5+import Prelude
46import Test.Tasty (TestTree, testGroup)
57import Tests.Helpers ((=?>))
68import Tests.Readers.Org.Shared ((=:), spcSep)
test/Tests/Readers/Org/Meta.hs.orignew file+191
@@ -0,0 +1,191 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Org.Meta (tests) where
3+
4+import Test.Tasty (TestTree, testGroup)
5+import Tests.Helpers ((=?>))
6+import Tests.Readers.Org.Shared ((=:), spcSep)
7+import Text.Pandoc
8+import Text.Pandoc.Builder
9+import qualified Data.Text as T
10+
11+tests :: [TestTree]
12+tests =
13+ [ "Comment" =:
14+ "# Nothing to see here" =?>
15+ (mempty::Blocks)
16+
17+ , "Not a comment" =:
18+ "#-tag" =?>
19+ para "#-tag"
20+
21+ , "Comment surrounded by Text" =:
22+ T.unlines [ "Before"
23+ , "# Comment"
24+ , "After"
25+ ] =?>
26+ mconcat [ para "Before"
27+ , para "After"
28+ ]
29+
30+ , "Title" =:
31+ "#+TITLE: Hello, World" =?>
32+ let titleInline = toList $ "Hello," <> space <> "World"
33+ meta = setMeta "title" (MetaInlines titleInline) nullMeta
34+ in Pandoc meta mempty
35+
36+ , "Author" =:
37+ "#+author: John /Emacs-Fanboy/ Doe" =?>
38+ let author = toList . spcSep $ [ "John", emph "Emacs-Fanboy", "Doe" ]
39+ meta = setMeta "author" (MetaList [MetaInlines author]) nullMeta
40+ in Pandoc meta mempty
41+
42+ , "Multiple authors" =:
43+ "#+author: James Dewey Watson, Francis Harry Compton Crick " =?>
44+ let watson = MetaInlines $ toList "James Dewey Watson"
45+ crick = MetaInlines $ toList "Francis Harry Compton Crick"
46+ meta = setMeta "author" (MetaList [watson, crick]) nullMeta
47+ in Pandoc meta mempty
48+
49+ , "Date" =:
50+ "#+Date: Feb. *28*, 2014" =?>
51+ let date = toList . spcSep $ [ "Feb.", strong "28" <> ",", "2014" ]
52+ meta = setMeta "date" (MetaInlines date) nullMeta
53+ in Pandoc meta mempty
54+
55+ , "Description" =:
56+ "#+DESCRIPTION: Explanatory text" =?>
57+ let description = "Explanatory text"
58+ meta = setMeta "description" (MetaString description) nullMeta
59+ in Pandoc meta mempty
60+
61+ , "Properties drawer" =:
62+ T.unlines [ " :PROPERTIES:"
63+ , " :setting: foo"
64+ , " :END:"
65+ ] =?>
66+ (mempty::Blocks)
67+
68+ , "LaTeX_headers options are translated to header-includes" =:
69+ "#+LaTeX_header: \\usepackage{tikz}" =?>
70+ let latexInlines = rawInline "latex" "\\usepackage{tikz}"
71+ inclList = MetaList [MetaInlines (toList latexInlines)]
72+ meta = setMeta "header-includes" inclList nullMeta
73+ in Pandoc meta mempty
74+
75+ , "LaTeX_class option is translated to documentclass" =:
76+ "#+LATEX_CLASS: article" =?>
77+ let meta = setMeta "documentclass" (MetaString "article") nullMeta
78+ in Pandoc meta mempty
79+
80+ , "LaTeX_class_options is translated to classoption" =:
81+ "#+LATEX_CLASS_OPTIONS: [a4paper]" =?>
82+ let meta = setMeta "classoption" (MetaString "a4paper") nullMeta
83+ in Pandoc meta mempty
84+
85+ , "LaTeX_class_options is translated to classoption" =:
86+ "#+html_head: <meta/>" =?>
87+ let html = rawInline "html" "<meta/>"
88+ inclList = MetaList [MetaInlines (toList html)]
89+ meta = setMeta "header-includes" inclList nullMeta
90+ in Pandoc meta mempty
91+
92+ , "later meta definitions take precedence" =:
93+ T.unlines [ "#+AUTHOR: this will not be used"
94+ , "#+author: Max"
95+ ] =?>
96+ let author = MetaInlines [Str "Max"]
97+ meta = setMeta "author" (MetaList [author]) nullMeta
98+ in Pandoc meta mempty
99+
100+ , "Logbook drawer" =:
101+ T.unlines [ " :LogBook:"
102+ , " - State \"DONE\" from \"TODO\" [2014-03-03 Mon 11:00]"
103+ , " :END:"
104+ ] =?>
105+ (mempty::Blocks)
106+
107+ , "Drawer surrounded by text" =:
108+ T.unlines [ "Before"
109+ , ":PROPERTIES:"
110+ , ":END:"
111+ , "After"
112+ ] =?>
113+ para "Before" <> para "After"
114+
115+ , "Drawer markers must be the only text in the line" =:
116+ T.unlines [ " :LOGBOOK: foo"
117+ , " :END: bar"
118+ ] =?>
119+ para (":LOGBOOK: foo" <> softbreak <> ":END: bar")
120+
121+ , "Drawers can be arbitrary" =:
122+ T.unlines [ ":FOO:"
123+ , "/bar/"
124+ , ":END:"
125+ ] =?>
126+ divWith (mempty, ["FOO", "drawer"], mempty) (para $ emph "bar")
127+
128+ , "Anchor reference" =:
129+ T.unlines [ "<<link-here>> Target."
130+ , ""
131+ , "[[link-here][See here!]]"
132+ ] =?>
133+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
134+ para (link "#link-here" "" ("See" <> space <> "here!")))
135+
136+ , "Search links are read as emph" =:
137+ "[[Wally][Where's Wally?]]" =?>
138+ para (emph $ "Where's" <> space <> "Wally?")
139+
140+ , "Link to nonexistent anchor" =:
141+ T.unlines [ "<<link-here>> Target."
142+ , ""
143+ , "[[link$here][See here!]]"
144+ ] =?>
145+ (para (spanWith ("link-here", [], []) mempty <> "Target.") <>
146+ para (emph ("See" <> space <> "here!")))
147+
148+ , "Link abbreviation" =:
149+ T.unlines [ "#+LINK: wp https://en.wikipedia.org/wiki/%s"
150+ , "[[wp:Org_mode][Wikipedia on Org-mode]]"
151+ ] =?>
152+ para (link "https://en.wikipedia.org/wiki/Org_mode" ""
153+ ("Wikipedia" <> space <> "on" <> space <> "Org-mode"))
154+
155+ , "Link abbreviation, defined after first use" =:
156+ T.unlines [ "[[zl:non-sense][Non-sense articles]]"
157+ , "#+LINK: zl http://zeitlens.com/tags/%s.html"
158+ ] =?>
159+ para (link "http://zeitlens.com/tags/non-sense.html" ""
160+ ("Non-sense" <> space <> "articles"))
161+
162+ , "Link abbreviation, URL encoded arguments" =:
163+ T.unlines [ "#+link: expl http://example.com/%h/foo"
164+ , "[[expl:Hello, World!][Moin!]]"
165+ ] =?>
166+ para (link "http://example.com/Hello%2C%20World%21/foo" "" "Moin!")
167+
168+ , "Link abbreviation, append arguments" =:
169+ T.unlines [ "#+link: expl http://example.com/"
170+ , "[[expl:foo][bar]]"
171+ ] =?>
172+ para (link "http://example.com/foo" "" "bar")
173+
174+ , testGroup "emphasis config"
175+ [ "Changing pre and post chars for emphasis" =:
176+ T.unlines [ "#+pandoc-emphasis-pre: \"[)\""
177+ , "#+pandoc-emphasis-post: \"]\\n\""
178+ , "([/emph/])*foo*"
179+ ] =?>
180+ para ("([" <> emph "emph" <> "])" <> strong "foo")
181+
182+ , "setting an invalid value restores the default" =:
183+ T.unlines [ "#+pandoc-emphasis-pre: \"[\""
184+ , "#+pandoc-emphasis-post: \"]\""
185+ , "#+pandoc-emphasis-pre:"
186+ , "#+pandoc-emphasis-post:"
187+ , "[/noemph/]"
188+ ] =?>
189+ para ("[/noemph/]")
190+ ]
191+ ]
test/Tests/Readers/Org/Shared.hs+2
@@ -1,3 +1,4 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Readers.Org.Shared
23 ( (=:)
34 , org
@@ -5,6 +6,7 @@ module Tests.Readers.Org.Shared
56 , tagSpan
67 ) where
78
9+import Prelude
810import Data.List (intersperse)
911import Data.Text (Text)
1012import Tests.Helpers (ToString, purely, test)
test/Tests/Readers/Org/Shared.hs.orignew file+29
@@ -0,0 +1,29 @@
1+module Tests.Readers.Org.Shared
2+ ( (=:)
3+ , org
4+ , spcSep
5+ , tagSpan
6+ ) where
7+
8+import Data.List (intersperse)
9+import Data.Text (Text)
10+import Tests.Helpers (ToString, purely, test)
11+import Test.Tasty (TestTree)
12+import Text.Pandoc (Pandoc, ReaderOptions (readerExtensions),
13+ def, getDefaultExtensions, readOrg)
14+import Text.Pandoc.Builder (Inlines, smallcaps, space, spanWith, str)
15+
16+org :: Text -> Pandoc
17+org = purely $ readOrg def{ readerExtensions = getDefaultExtensions "org" }
18+
19+infix 4 =:
20+(=:) :: ToString c
21+ => String -> (Text, c) -> TestTree
22+(=:) = test org
23+
24+spcSep :: [Inlines] -> Inlines
25+spcSep = mconcat . intersperse space
26+
27+-- | Create a span for the given tag.
28+tagSpan :: String -> Inlines
29+tagSpan t = spanWith ("", ["tag"], [("tag-name", t)]) . smallcaps $ str t
test/Tests/Readers/RST.hs+3−1
@@ -1,7 +1,9 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23{-# LANGUAGE ScopedTypeVariables #-}
34module Tests.Readers.RST (tests) where
45
6+import Prelude
57import Data.Text (Text)
68import qualified Data.Text as T
79import Test.Tasty
@@ -184,6 +186,6 @@ tests = [ "line block with blank line" =:
184186 , ".. [1]"
185187 , " bar"
186188 ] =?>
187− para ("foo" <> (note $ para "bar"))
189+ para ("foo" <> note (para "bar"))
188190 ]
189191 ]
test/Tests/Readers/RST.hs.orignew file+189
@@ -0,0 +1,189 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+module Tests.Readers.RST (tests) where
4+
5+import Data.Text (Text)
6+import qualified Data.Text as T
7+import Test.Tasty
8+import Tests.Helpers
9+import Text.Pandoc
10+import Text.Pandoc.Arbitrary ()
11+import Text.Pandoc.Builder
12+
13+rst :: Text -> Pandoc
14+rst = purely $ readRST def{ readerStandalone = True }
15+
16+infix 4 =:
17+(=:) :: ToString c
18+ => String -> (Text, c) -> TestTree
19+(=:) = test rst
20+
21+tests :: [TestTree]
22+tests = [ "line block with blank line" =:
23+ "| a\n|\n| b" =?> lineBlock [ "a", mempty, "\160b" ]
24+ , testGroup "field list"
25+ [ "general" =: T.unlines
26+ [ "para"
27+ , ""
28+ , ":Hostname: media08"
29+ , ":IP address: 10.0.0.19"
30+ , ":Size: 3ru"
31+ , ":Version: 1"
32+ , ":Indentation: Since the field marker may be quite long, the second"
33+ , " and subsequent lines of the field body do not have to line up"
34+ , " with the first line, but they must be indented relative to the"
35+ , " field name marker, and they must line up with each other."
36+ , ":Parameter i: integer"
37+ , ":Final: item"
38+ , " on two lines" ]
39+ =?>
40+ doc (para "para" <>
41+ definitionList [ (str "Hostname", [para "media08"])
42+ , (text "IP address", [para "10.0.0.19"])
43+ , (str "Size", [para "3ru"])
44+ , (str "Version", [para "1"])
45+ , (str "Indentation", [para "Since the field marker may be quite long, the second\nand subsequent lines of the field body do not have to line up\nwith the first line, but they must be indented relative to the\nfield name marker, and they must line up with each other."])
46+ , (text "Parameter i", [para "integer"])
47+ , (str "Final", [para "item\non two lines"])
48+ ])
49+ , "metadata" =: T.unlines
50+ [ "====="
51+ , "Title"
52+ , "====="
53+ , "--------"
54+ , "Subtitle"
55+ , "--------"
56+ , ""
57+ , ":Version: 1"
58+ ]
59+ =?>
60+ setMeta "version" (para "1") (setMeta "title" ("Title" :: Inlines)
61+ $ setMeta "subtitle" ("Subtitle" :: Inlines)
62+ $ doc mempty)
63+ , "with inline markup" =: T.unlines
64+ [ ":*Date*: today"
65+ , ""
66+ , ".."
67+ , ""
68+ , ":*one*: emphasis"
69+ , ":two_: reference"
70+ , ":`three`_: another one"
71+ , ":``four``: literal"
72+ , ""
73+ , ".. _two: http://example.com"
74+ , ".. _three: http://example.org"
75+ ]
76+ =?>
77+ setMeta "date" (str "today") (doc
78+ $ definitionList [ (emph "one", [para "emphasis"])
79+ , (link "http://example.com" "" "two", [para "reference"])
80+ , (link "http://example.org" "" "three", [para "another one"])
81+ , (code "four", [para "literal"])
82+ ])
83+ ]
84+ , "URLs with following punctuation" =:
85+ ("http://google.com, http://yahoo.com; http://foo.bar.baz.\n" <>
86+ "http://foo.bar/baz_(bam) (http://foo.bar)") =?>
87+ para (link "http://google.com" "" "http://google.com" <> ", " <>
88+ link "http://yahoo.com" "" "http://yahoo.com" <> "; " <>
89+ link "http://foo.bar.baz" "" "http://foo.bar.baz" <> ". " <>
90+ softbreak <>
91+ link "http://foo.bar/baz_(bam)" "" "http://foo.bar/baz_(bam)"
92+ <> " (" <> link "http://foo.bar" "" "http://foo.bar" <> ")")
93+ , "Reference names with special characters" =:
94+ ("A-1-B_2_C:3:D+4+E.5.F_\n\n" <>
95+ ".. _A-1-B_2_C:3:D+4+E.5.F: https://example.com\n") =?>
96+ para (link "https://example.com" "" "A-1-B_2_C:3:D+4+E.5.F")
97+ , "Code directive with class and number-lines" =: T.unlines
98+ [ ".. code::python"
99+ , " :number-lines: 34"
100+ , " :class: class1 class2 class3"
101+ , ""
102+ , " def func(x):"
103+ , " return y"
104+ ] =?>
105+ doc (codeBlockWith
106+ ( ""
107+ , ["sourceCode", "python", "numberLines", "class1", "class2", "class3"]
108+ , [ ("startFrom", "34") ]
109+ )
110+ "def func(x):\n return y")
111+ , "Code directive with number-lines, no line specified" =: T.unlines
112+ [ ".. code::python"
113+ , " :number-lines: "
114+ , ""
115+ , " def func(x):"
116+ , " return y"
117+ ] =?>
118+ doc (codeBlockWith
119+ ( ""
120+ , ["sourceCode", "python", "numberLines"]
121+ , [ ("startFrom", "") ]
122+ )
123+ "def func(x):\n return y")
124+ , testGroup "literal / line / code blocks"
125+ [ "indented literal block" =: T.unlines
126+ [ "::"
127+ , ""
128+ , " block quotes"
129+ , ""
130+ , " can go on for many lines"
131+ , "but must stop here"]
132+ =?>
133+ doc (
134+ codeBlock "block quotes\n\ncan go on for many lines" <>
135+ para "but must stop here")
136+ , "line block with 3 lines" =: "| a\n| b\n| c"
137+ =?> lineBlock ["a", "b", "c"]
138+ , "line blocks with blank lines" =: T.unlines
139+ [ "|"
140+ , ""
141+ , "|"
142+ , "| a"
143+ , "| b"
144+ , "|"
145+ , ""
146+ , "|"
147+ ] =?>
148+ lineBlock [""] <>
149+ lineBlock ["", "a", "b", ""] <>
150+ lineBlock [""]
151+ , "quoted literal block using >" =: "::\n\n> quoted\n> block\n\nOrdinary paragraph"
152+ =?> codeBlock "> quoted\n> block" <> para "Ordinary paragraph"
153+ , "quoted literal block using | (not a line block)" =: "::\n\n| quoted\n| block\n\nOrdinary paragraph"
154+ =?> codeBlock "| quoted\n| block" <> para "Ordinary paragraph"
155+ , "class directive with single paragraph" =: ".. class:: special\n\nThis is a \"special\" paragraph."
156+ =?> divWith ("", ["special"], []) (para "This is a \"special\" paragraph.")
157+ , "class directive with two paragraphs" =: ".. class:: exceptional remarkable\n\n First paragraph.\n\n Second paragraph."
158+ =?> divWith ("", ["exceptional", "remarkable"], []) (para "First paragraph." <> para "Second paragraph.")
159+ , "class directive around literal block" =: ".. class:: classy\n\n::\n\n a\n b"
160+ =?> divWith ("", ["classy"], []) (codeBlock "a\nb")]
161+ , testGroup "interpreted text roles"
162+ [ "literal role prefix" =: ":literal:`a`" =?> para (code "a")
163+ , "literal role postfix" =: "`a`:literal:" =?> para (code "a")
164+ , "literal text" =: "``text``" =?> para (code "text")
165+ , "code role" =: ":code:`a`" =?> para (codeWith ("", ["sourceCode"], []) "a")
166+ , "inherited code role" =: ".. role:: codeLike(code)\n\n:codeLike:`a`"
167+ =?> para (codeWith ("", ["codeLike", "sourceCode"], []) "a")
168+ , "custom code role with language field"
169+ =: ".. role:: lhs(code)\n :language: haskell\n\n:lhs:`a`"
170+ =?> para (codeWith ("", ["lhs", "haskell","sourceCode"], []) "a")
171+ , "custom role with unspecified parent role"
172+ =: ".. role:: classy\n\n:classy:`text`"
173+ =?> para (spanWith ("", ["classy"], []) "text")
174+ , "role with recursive inheritance"
175+ =: ".. role:: haskell(code)\n.. role:: lhs(haskell)\n\n:lhs:`text`"
176+ =?> para (codeWith ("", ["lhs", "haskell", "sourceCode"], []) "text")
177+ , "unknown role" =: ":unknown:`text`" =?>
178+ para (spanWith ("",[],[("role","unknown")]) (str "text"))
179+ ]
180+ , testGroup "footnotes"
181+ [ "remove space before note" =: T.unlines
182+ [ "foo [1]_"
183+ , ""
184+ , ".. [1]"
185+ , " bar"
186+ ] =?>
187+ para ("foo" <> note (para "bar"))
188+ ]
189+ ]
test/Tests/Readers/Txt2Tags.hs+3−1
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Readers.Txt2Tags (tests) where
34
5+import Prelude
46import Data.List (intersperse)
57import Data.Text (Text)
68import qualified Data.Text as T
@@ -143,7 +145,7 @@ tests =
143145
144146 , "Header with label" =:
145147 "= header =[label]" =?>
146− headerWith ("label", [], []) 1 ("header")
148+ headerWith ("label", [], []) 1 "header"
147149
148150 , "Invalid header, mismatched delimiters" =:
149151 "== header =" =?>
test/Tests/Readers/Txt2Tags.hs.orignew file+437
@@ -0,0 +1,437 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Readers.Txt2Tags (tests) where
3+
4+import Data.List (intersperse)
5+import Data.Text (Text)
6+import qualified Data.Text as T
7+import Test.Tasty
8+import Tests.Helpers
9+import Text.Pandoc
10+import Text.Pandoc.Arbitrary ()
11+import Text.Pandoc.Builder
12+import Text.Pandoc.Shared (underlineSpan)
13+
14+t2t :: Text -> Pandoc
15+-- t2t = handleError . readTxt2Tags (T2TMeta "date" "mtime" "in" "out") def
16+t2t = purely $ \s -> do
17+ setInputFiles ["in"]
18+ setOutputFile (Just "out")
19+ readTxt2Tags def s
20+
21+infix 4 =:
22+(=:) :: ToString c
23+ => String -> (Text, c) -> TestTree
24+(=:) = test t2t
25+
26+spcSep :: [Inlines] -> Inlines
27+spcSep = mconcat . intersperse space
28+
29+simpleTable' :: Int
30+ -> [Blocks]
31+ -> [[Blocks]]
32+ -> Blocks
33+simpleTable' n = table "" (replicate n (AlignCenter, 0.0))
34+
35+tests :: [TestTree]
36+tests =
37+ [ testGroup "Inlines"
38+ [ "Plain String" =:
39+ "Hello, World" =?>
40+ para (spcSep [ "Hello,", "World" ])
41+
42+ , "Emphasis" =:
43+ "//Planet Punk//" =?>
44+ para (emph . spcSep $ ["Planet", "Punk"])
45+
46+ , "Strong" =:
47+ "**Cider**" =?>
48+ para (strong "Cider")
49+
50+ , "Strong Emphasis" =:
51+ "//**strength**//" =?>
52+ para (emph . strong $ "strength")
53+
54+ , "Strikeout" =:
55+ "--Kill Bill--" =?>
56+ para (strikeout . spcSep $ [ "Kill", "Bill" ])
57+
58+ , "Verbatim" =:
59+ "``Robot.rock()``" =?>
60+ para (code "Robot.rock()")
61+
62+ , "Symbol" =:
63+ "A * symbol" =?>
64+ para (str "A" <> space <> str "*" <> space <> "symbol")
65+
66+ , "No empty markup" =:
67+ "//// **** ____ ---- ```` \"\"\"\" ''''" =?>
68+ para (spcSep [ "////", "****", "____", "----", "````", "\"\"\"\"", "''''" ])
69+
70+ , "Inline markup is greedy" =:
71+ "***** ///// _____ ----- ````` \"\"\"\"\" '''''" =?>
72+ para (spcSep [strong "*", emph "/", underlineSpan "_"
73+ , strikeout "-", code "`", text "\""
74+ , rawInline "html" "'"])
75+ , "Markup must be greedy" =:
76+ "********** ////////// __________ ---------- `````````` \"\"\"\"\"\"\"\"\"\" ''''''''''" =?>
77+ para (spcSep [strong "******", emph "//////", underlineSpan "______"
78+ , strikeout "------", code "``````", text "\"\"\"\"\"\""
79+ , rawInline "html" "''''''"])
80+ , "Inlines must be glued" =:
81+ "** a** **a ** ** a **" =?>
82+ para (text "** a** **a ** ** a **")
83+
84+ , "Macros: Date" =:
85+ "%%date" =?>
86+ para "1970-01-01"
87+ , "Macros: Mod Time" =:
88+ "%%mtime" =?>
89+ para (str "")
90+ , "Macros: Infile" =:
91+ "%%infile" =?>
92+ para "in"
93+ , "Macros: Outfile" =:
94+ "%%outfile" =?>
95+ para "out"
96+ , "Autolink" =:
97+ "http://www.google.com" =?>
98+ para (link "http://www.google.com" "" (str "http://www.google.com"))
99+ , "JPEG Image" =:
100+ "[image.jpg]" =?>
101+ para (image "image.jpg" "" mempty)
102+ , "PNG Image" =:
103+ "[image.png]" =?>
104+ para (image "image.png" "" mempty)
105+
106+ , "Link" =:
107+ "[title http://google.com]" =?>
108+ para (link "http://google.com" "" (str "title"))
109+
110+ , "Image link" =:
111+ "[[image.jpg] abc]" =?>
112+ para (link "abc" "" (image "image.jpg" "" mempty))
113+ , "Invalid link: No trailing space" =:
114+ "[title invalid ]" =?>
115+ para (text "[title invalid ]")
116+
117+
118+ ]
119+
120+ , testGroup "Basic Blocks"
121+ ["Paragraph, lines grouped together" =:
122+ "A paragraph\n A blank line ends the \n current paragraph\n"
123+ =?> para "A paragraph\n A blank line ends the\n current paragraph"
124+ , "Paragraph, ignore leading and trailing spaces" =:
125+ " Leading and trailing spaces are ignored. \n" =?>
126+ para "Leading and trailing spaces are ignored."
127+ , "Comment line in paragraph" =:
128+ "A comment line can be placed inside a paragraph.\n% this comment will be ignored \nIt will not affect it.\n"
129+ =?> para "A comment line can be placed inside a paragraph.\nIt will not affect it."
130+ , "Paragraph" =:
131+ "Paragraph\n" =?>
132+ para "Paragraph"
133+
134+ , "First Level Header" =:
135+ "+ Headline +\n" =?>
136+ header 1 "Headline"
137+
138+ , "Third Level Header" =:
139+ "=== Third Level Headline ===\n" =?>
140+ header 3 ("Third" <> space <>
141+ "Level" <> space <>
142+ "Headline")
143+
144+ , "Header with label" =:
145+ "= header =[label]" =?>
146+ headerWith ("label", [], []) 1 "header"
147+
148+ , "Invalid header, mismatched delimiters" =:
149+ "== header =" =?>
150+ para (text "== header =")
151+
152+ , "Invalid header, spaces in label" =:
153+ "== header ==[ haha ]" =?>
154+ para (text "== header ==[ haha ]")
155+
156+ , "Invalid header, invalid label character" =:
157+ "== header ==[lab/el]" =?>
158+ para (text "== header ==[lab/el]")
159+ , "Headers not preceded by a blank line" =:
160+ T.unlines [ "++ eat dinner ++"
161+ , "Spaghetti and meatballs tonight."
162+ , "== walk dog =="
163+ ] =?>
164+ mconcat [ header 2 ("eat" <> space <> "dinner")
165+ , para $ spcSep [ "Spaghetti", "and", "meatballs", "tonight." ]
166+ , header 2 ("walk" <> space <> "dog")
167+ ]
168+
169+ , "Paragraph starting with an equals" =:
170+ "=five" =?>
171+ para "=five"
172+
173+ , "Paragraph containing asterisk at beginning of line" =:
174+ T.unlines [ "lucky"
175+ , "*star"
176+ ] =?>
177+ para ("lucky" <> softbreak <> "*star")
178+
179+ , "Horizontal Rule" =:
180+ T.unlines [ "before"
181+ , T.replicate 20 "-"
182+ , T.replicate 20 "="
183+ , T.replicate 20 "_"
184+ , "after"
185+ ] =?>
186+ mconcat [ para "before"
187+ , horizontalRule
188+ , horizontalRule
189+ , horizontalRule
190+ , para "after"
191+ ]
192+
193+ , "Comment Block" =:
194+ T.unlines [ "%%%"
195+ , "stuff"
196+ , "bla"
197+ , "%%%"] =?>
198+ (mempty::Blocks)
199+
200+
201+ ]
202+
203+ , testGroup "Lists"
204+ [ "Simple Bullet Lists" =:
205+ ("- Item1\n" <>
206+ "- Item2\n") =?>
207+ bulletList [ plain "Item1"
208+ , plain "Item2"
209+ ]
210+
211+ , "Indented Bullet Lists" =:
212+ (" - Item1\n" <>
213+ " - Item2\n") =?>
214+ bulletList [ plain "Item1"
215+ , plain "Item2"
216+ ]
217+
218+
219+
220+ , "Nested Bullet Lists" =:
221+ ("- Discovery\n" <>
222+ " + One More Time\n" <>
223+ " + Harder, Better, Faster, Stronger\n" <>
224+ "- Homework\n" <>
225+ " + Around the World\n"<>
226+ "- Human After All\n" <>
227+ " + Technologic\n" <>
228+ " + Robot Rock\n") =?>
229+ bulletList [ mconcat
230+ [ plain "Discovery"
231+ , orderedList [ plain ("One" <> space <>
232+ "More" <> space <>
233+ "Time")
234+ , plain ("Harder," <> space <>
235+ "Better," <> space <>
236+ "Faster," <> space <>
237+ "Stronger")
238+ ]
239+ ]
240+ , mconcat
241+ [ plain "Homework"
242+ , orderedList [ plain ("Around" <> space <>
243+ "the" <> space <>
244+ "World")
245+ ]
246+ ]
247+ , mconcat
248+ [ plain ("Human" <> space <> "After" <> space <> "All")
249+ , orderedList [ plain "Technologic"
250+ , plain ("Robot" <> space <> "Rock")
251+ ]
252+ ]
253+ ]
254+
255+ , "Simple Ordered List" =:
256+ ("+ Item1\n" <>
257+ "+ Item2\n") =?>
258+ let listStyle = (1, DefaultStyle, DefaultDelim)
259+ listStructure = [ plain "Item1"
260+ , plain "Item2"
261+ ]
262+ in orderedListWith listStyle listStructure
263+
264+
265+ , "Indented Ordered List" =:
266+ (" + Item1\n" <>
267+ " + Item2\n") =?>
268+ let listStyle = (1, DefaultStyle, DefaultDelim)
269+ listStructure = [ plain "Item1"
270+ , plain "Item2"
271+ ]
272+ in orderedListWith listStyle listStructure
273+
274+ , "Nested Ordered Lists" =:
275+ ("+ One\n" <>
276+ " + One-One\n" <>
277+ " + One-Two\n" <>
278+ "+ Two\n" <>
279+ " + Two-One\n"<>
280+ " + Two-Two\n") =?>
281+ let listStyle = (1, DefaultStyle, DefaultDelim)
282+ listStructure = [ mconcat
283+ [ plain "One"
284+ , orderedList [ plain "One-One"
285+ , plain "One-Two"
286+ ]
287+ ]
288+ , mconcat
289+ [ plain "Two"
290+ , orderedList [ plain "Two-One"
291+ , plain "Two-Two"
292+ ]
293+ ]
294+ ]
295+ in orderedListWith listStyle listStructure
296+
297+ , "Ordered List in Bullet List" =:
298+ ("- Emacs\n" <>
299+ " + Org\n") =?>
300+ bulletList [ (plain "Emacs") <>
301+ (orderedList [ plain "Org"])
302+ ]
303+
304+ , "Bullet List in Ordered List" =:
305+ ("+ GNU\n" <>
306+ " - Freedom\n") =?>
307+ orderedList [ (plain "GNU") <> bulletList [ (plain "Freedom") ] ]
308+
309+ , "Definition List" =:
310+ T.unlines [ ": PLL"
311+ , " phase-locked loop"
312+ , ": TTL"
313+ , " transistor-transistor logic"
314+ , ": PSK"
315+ , " a digital"
316+ ] =?>
317+ definitionList [ ("PLL", [ plain $ "phase-locked" <> space <> "loop" ])
318+ , ("TTL", [ plain $ "transistor-transistor" <> space <> "logic" ])
319+ , ("PSK", [ plain $ "a" <> space <> "digital" ])
320+ ]
321+
322+
323+ , "Loose bullet list" =:
324+ T.unlines [ "- apple"
325+ , ""
326+ , "- orange"
327+ , ""
328+ , "- peach"
329+ ] =?>
330+ bulletList [ para "apple"
331+ , para "orange"
332+ , para "peach"
333+ ]
334+ ]
335+
336+ , testGroup "Tables"
337+ [ "Single cell table" =:
338+ "| Test " =?>
339+ simpleTable' 1 mempty [[plain "Test"]]
340+
341+ , "Multi cell table" =:
342+ "| One | Two |" =?>
343+ simpleTable' 2 mempty [ [ plain "One", plain "Two" ] ]
344+
345+ , "Multi line table" =:
346+ T.unlines [ "| One |"
347+ , "| Two |"
348+ , "| Three |"
349+ ] =?>
350+ simpleTable' 1 mempty
351+ [ [ plain "One" ]
352+ , [ plain "Two" ]
353+ , [ plain "Three" ]
354+ ]
355+
356+ , "Empty table" =:
357+ "| |" =?>
358+ simpleTable' 1 mempty [[mempty]]
359+
360+ , "Glider Table" =:
361+ T.unlines [ "| 1 | 0 | 0 |"
362+ , "| 0 | 1 | 1 |"
363+ , "| 1 | 1 | 0 |"
364+ ] =?>
365+ simpleTable' 3 mempty
366+ [ [ plain "1", plain "0", plain "0" ]
367+ , [ plain "0", plain "1", plain "1" ]
368+ , [ plain "1", plain "1", plain "0" ]
369+ ]
370+
371+
372+ , "Table with Header" =:
373+ T.unlines [ "|| Species | Status |"
374+ , "| cervisiae | domesticated |"
375+ , "| paradoxus | wild |"
376+ ] =?>
377+ simpleTable [ plain "Species", plain "Status" ]
378+ [ [ plain "cervisiae", plain "domesticated" ]
379+ , [ plain "paradoxus", plain "wild" ]
380+ ]
381+
382+ , "Table alignment determined by spacing" =:
383+ T.unlines [ "| Numbers | Text | More |"
384+ , "| 1 | One | foo |"
385+ , "| 2 | Two | bar |"
386+ ] =?>
387+ table "" (zip [AlignCenter, AlignRight, AlignDefault] [0, 0, 0])
388+ []
389+ [ [ plain "Numbers", plain "Text", plain "More" ]
390+ , [ plain "1" , plain "One" , plain "foo" ]
391+ , [ plain "2" , plain "Two" , plain "bar" ]
392+ ]
393+
394+ , "Pipe within text doesn't start a table" =:
395+ "Ceci n'est pas une | pipe " =?>
396+ para (spcSep [ "Ceci", "n'est", "pas", "une", "|", "pipe" ])
397+
398+
399+ , "Table with differing row lengths" =:
400+ T.unlines [ "|| Numbers | Text "
401+ , "| 1 | One | foo |"
402+ , "| 2 "
403+ ] =?>
404+ table "" (zip [AlignCenter, AlignLeft, AlignLeft] [0, 0, 0])
405+ [ plain "Numbers", plain "Text" , plain mempty ]
406+ [ [ plain "1" , plain "One" , plain "foo" ]
407+ , [ plain "2" , plain mempty , plain mempty ]
408+ ]
409+
410+ ]
411+
412+ , testGroup "Blocks and fragments"
413+ [ "Source block" =:
414+ T.unlines [ "```"
415+ , "main = putStrLn greeting"
416+ , " where greeting = \"moin\""
417+ , "```" ] =?>
418+ let code' = "main = putStrLn greeting\n" <>
419+ " where greeting = \"moin\"\n"
420+ in codeBlock code'
421+
422+ , "tagged block" =:
423+ T.unlines [ "'''"
424+ , "<aside>HTML5 is pretty nice.</aside>"
425+ , "'''"
426+ ] =?>
427+ rawBlock "html" "<aside>HTML5 is pretty nice.</aside>\n"
428+
429+ , "Quote block" =:
430+ T.unlines ["\t//Niemand// hat die Absicht, eine Mauer zu errichten!"
431+ ] =?>
432+ blockQuote (para (spcSep [ emph "Niemand", "hat", "die", "Absicht,"
433+ , "eine", "Mauer", "zu", "errichten!"
434+ ]))
435+
436+ ]
437+ ]
test/Tests/Shared.hs+2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Shared (tests) where
23
4+import Prelude
35import System.FilePath.Posix (joinPath)
46import Test.Tasty
57import Test.Tasty.HUnit (assertBool, testCase, (@?=))
test/Tests/Shared.hs.orignew file+39
@@ -0,0 +1,39 @@
1+module Tests.Shared (tests) where
2+
3+import System.FilePath.Posix (joinPath)
4+import Test.Tasty
5+import Test.Tasty.HUnit (assertBool, testCase, (@?=))
6+import Text.Pandoc.Arbitrary ()
7+import Text.Pandoc.Builder
8+import Text.Pandoc.Shared
9+
10+tests :: [TestTree]
11+tests = [ testGroup "compactifyDL"
12+ [ testCase "compactifyDL with empty def" $
13+ assertBool "compactifyDL"
14+ (let x = [(str "word", [para (str "def"), mempty])]
15+ in compactifyDL x == x)
16+ ]
17+ , testGroup "collapseFilePath" testCollapse
18+ ]
19+
20+testCollapse :: [TestTree]
21+testCollapse = map (testCase "collapse")
22+ [ collapseFilePath (joinPath [ ""]) @?= (joinPath [ ""])
23+ , collapseFilePath (joinPath [ ".","foo"]) @?= (joinPath [ "foo"])
24+ , collapseFilePath (joinPath [ ".",".","..","foo"]) @?= (joinPath [ joinPath ["..", "foo"]])
25+ , collapseFilePath (joinPath [ "..","foo"]) @?= (joinPath [ "..","foo"])
26+ , collapseFilePath (joinPath [ "","bar","..","baz"]) @?= (joinPath [ "","baz"])
27+ , collapseFilePath (joinPath [ "","..","baz"]) @?= (joinPath [ "","..","baz"])
28+ , collapseFilePath (joinPath [ ".","foo","..",".","bar","..",".",".","baz"]) @?= (joinPath [ "baz"])
29+ , collapseFilePath (joinPath [ ".",""]) @?= (joinPath [ ""])
30+ , collapseFilePath (joinPath [ ".",".",""]) @?= (joinPath [ ""])
31+ , collapseFilePath (joinPath [ "..",""]) @?= (joinPath [ ".."])
32+ , collapseFilePath (joinPath [ "..",".",""]) @?= (joinPath [ ".."])
33+ , collapseFilePath (joinPath [ ".","..",""]) @?= (joinPath [ ".."])
34+ , collapseFilePath (joinPath [ "..","..",""]) @?= (joinPath [ "..",".."])
35+ , collapseFilePath (joinPath [ "parent","foo","baz","..","bar"]) @?= (joinPath [ "parent","foo","bar"])
36+ , collapseFilePath (joinPath [ "parent","foo","baz","..","..","bar"]) @?= (joinPath [ "parent","bar"])
37+ , collapseFilePath (joinPath [ "parent","foo",".."]) @?= (joinPath [ "parent"])
38+ , collapseFilePath (joinPath [ "","parent","foo","..","..","bar"]) @?= (joinPath [ "","bar"])
39+ , collapseFilePath (joinPath [ "",".","parent","foo"]) @?= (joinPath [ "","parent","foo"])]
test/Tests/Writers/AsciiDoc.hs+2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Writers.AsciiDoc (tests) where
23
4+import Prelude
35import Data.Text (unpack)
46import Test.Tasty
57import Tests.Helpers
test/Tests/Writers/AsciiDoc.hs.orignew file+56
@@ -0,0 +1,56 @@
1+module Tests.Writers.AsciiDoc (tests) where
2+
3+import Data.Text (unpack)
4+import Test.Tasty
5+import Tests.Helpers
6+import Text.Pandoc
7+import Text.Pandoc.Arbitrary ()
8+import Text.Pandoc.Builder
9+
10+asciidoc :: (ToPandoc a) => a -> String
11+asciidoc = unpack . purely (writeAsciiDoc def{ writerWrapText = WrapNone }) . toPandoc
12+
13+tests :: [TestTree]
14+tests = [ testGroup "emphasis"
15+ [ test asciidoc "emph word before" $
16+ para (text "foo" <> emph (text "bar")) =?>
17+ "foo__bar__"
18+ , test asciidoc "emph word after" $
19+ para (emph (text "foo") <> text "bar") =?>
20+ "__foo__bar"
21+ , test asciidoc "emph quoted" $
22+ para (doubleQuoted (emph (text "foo"))) =?>
23+ "``__foo__''"
24+ , test asciidoc "strong word before" $
25+ para (text "foo" <> strong (text "bar")) =?>
26+ "foo**bar**"
27+ , test asciidoc "strong word after" $
28+ para (strong (text "foo") <> text "bar") =?>
29+ "**foo**bar"
30+ , test asciidoc "strong quoted" $
31+ para (singleQuoted (strong (text "foo"))) =?>
32+ "`**foo**'"
33+ ]
34+ , testGroup "tables"
35+ [ test asciidoc "empty cells" $
36+ simpleTable [] [[mempty],[mempty]] =?> unlines
37+ [ "[cols=\"\",]"
38+ , "|===="
39+ , "|"
40+ , "|"
41+ , "|===="
42+ ]
43+ , test asciidoc "multiblock cells" $
44+ simpleTable [] [[para (text "Para 1") <> para (text "Para 2")]]
45+ =?> unlines
46+ [ "[cols=\"\",]"
47+ , "|====="
48+ , "a|"
49+ , "Para 1"
50+ , ""
51+ , "Para 2"
52+ , ""
53+ , "|====="
54+ ]
55+ ]
56+ ]
test/Tests/Writers/ConTeXt.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.ConTeXt (tests) where
34
5+import Prelude
46import Data.Text (unpack)
57import Test.Tasty
68import Test.Tasty.QuickCheck
test/Tests/Writers/ConTeXt.hs.orignew file+149
@@ -0,0 +1,149 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.ConTeXt (tests) where
3+
4+import Data.Text (unpack)
5+import Test.Tasty
6+import Test.Tasty.QuickCheck
7+import Tests.Helpers
8+import Text.Pandoc
9+import Text.Pandoc.Arbitrary ()
10+import Text.Pandoc.Builder
11+
12+context :: (ToPandoc a) => a -> String
13+context = unpack . purely (writeConTeXt def) . toPandoc
14+
15+context' :: (ToPandoc a) => a -> String
16+context' = unpack . purely (writeConTeXt def{ writerWrapText = WrapNone }) . toPandoc
17+
18+contextNtb :: (ToPandoc a) => a -> String
19+contextNtb = unpack . purely (writeConTeXt def{ writerExtensions = enableExtension Ext_ntb pandocExtensions }) . toPandoc
20+
21+contextDiv :: (ToPandoc a) => a -> String
22+contextDiv = unpack . purely (writeConTeXt def{ writerSectionDivs = True }) . toPandoc
23+
24+{-
25+ "my test" =: X =?> Y
26+
27+is shorthand for
28+
29+ test context "my test" $ X =?> Y
30+
31+which is in turn shorthand for
32+
33+ test context "my test" (X,Y)
34+-}
35+
36+infix 4 =:
37+(=:) :: (ToString a, ToPandoc a)
38+ => String -> (a, String) -> TestTree
39+(=:) = test context
40+
41+tests :: [TestTree]
42+tests = [ testGroup "inline code"
43+ [ "with '}'" =: code "}" =?> "\\mono{\\}}"
44+ , "without '}'" =: code "]" =?> "\\type{]}"
45+ , testProperty "code property" $ \s -> null s ||
46+ if '{' `elem` s || '}' `elem` s
47+ then context' (code s) == "\\mono{" ++
48+ context' (str s) ++ "}"
49+ else context' (code s) == "\\type{" ++ s ++ "}"
50+ ]
51+ , testGroup "headers"
52+ [ "level 1" =:
53+ headerWith ("my-header",[],[]) 1 "My header" =?> "\\section[title={My header},reference={my-header}]"
54+ , test contextDiv "section-divs" $
55+ ( headerWith ("header1", [], []) 1 (text "Header1")
56+ <> headerWith ("header2", [], []) 2 (text "Header2")
57+ <> headerWith ("header3", [], []) 3 (text "Header3")
58+ <> headerWith ("header4", [], []) 4 (text "Header4")
59+ <> headerWith ("header5", [], []) 5 (text "Header5")
60+ <> headerWith ("header6", [], []) 6 (text "Header6"))
61+ =?>
62+ unlines [ "\\startsection[title={Header1},reference={header1}]\n"
63+ , "\\startsubsection[title={Header2},reference={header2}]\n"
64+ , "\\startsubsubsection[title={Header3},reference={header3}]\n"
65+ , "\\startsubsubsubsection[title={Header4},reference={header4}]\n"
66+ , "\\startsubsubsubsubsection[title={Header5},reference={header5}]\n"
67+ , "\\startsubsubsubsubsubsection[title={Header6},reference={header6}]\n"
68+ , "\\stopsubsubsubsubsubsection\n"
69+ , "\\stopsubsubsubsubsection\n"
70+ , "\\stopsubsubsubsection\n"
71+ , "\\stopsubsubsection\n"
72+ , "\\stopsubsection\n"
73+ , "\\stopsection" ]
74+ ]
75+ , testGroup "bullet lists"
76+ [ "nested" =:
77+ bulletList [
78+ plain (text "top")
79+ <> bulletList [
80+ plain (text "next")
81+ <> bulletList [plain (text "bot")]
82+ ]
83+ ] =?> unlines
84+ [ "\\startitemize[packed]"
85+ , "\\item"
86+ , " top"
87+ , " \\startitemize[packed]"
88+ , " \\item"
89+ , " next"
90+ , " \\startitemize[packed]"
91+ , " \\item"
92+ , " bot"
93+ , " \\stopitemize"
94+ , " \\stopitemize"
95+ , "\\stopitemize" ]
96+ ]
97+ , testGroup "natural tables"
98+ [ test contextNtb "table with header and caption" $
99+ let caption = text "Table 1"
100+ aligns = [(AlignRight, 0.0), (AlignLeft, 0.0), (AlignCenter, 0.0), (AlignDefault, 0.0)]
101+ headers = [plain $ text "Right",
102+ plain $ text "Left",
103+ plain $ text "Center",
104+ plain $ text "Default"]
105+ rows = [[plain $ text "1.1",
106+ plain $ text "1.2",
107+ plain $ text "1.3",
108+ plain $ text "1.4"]
109+ ,[plain $ text "2.1",
110+ plain $ text "2.2",
111+ plain $ text "2.3",
112+ plain $ text "2.4"]
113+ ,[plain $ text "3.1",
114+ plain $ text "3.2",
115+ plain $ text "3.3",
116+ plain $ text "3.4"]]
117+ in table caption aligns headers rows
118+ =?> unlines [ "\\startplacetable[title={Table 1}]"
119+ , "\\startTABLE"
120+ , "\\startTABLEhead"
121+ , "\\NC[align=left] Right"
122+ , "\\NC[align=right] Left"
123+ , "\\NC[align=middle] Center"
124+ , "\\NC Default"
125+ , "\\NC\\NR"
126+ , "\\stopTABLEhead"
127+ , "\\startTABLEbody"
128+ , "\\NC[align=left] 1.1"
129+ , "\\NC[align=right] 1.2"
130+ , "\\NC[align=middle] 1.3"
131+ , "\\NC 1.4"
132+ , "\\NC\\NR"
133+ , "\\NC[align=left] 2.1"
134+ , "\\NC[align=right] 2.2"
135+ , "\\NC[align=middle] 2.3"
136+ , "\\NC 2.4"
137+ , "\\NC\\NR"
138+ , "\\stopTABLEbody"
139+ , "\\startTABLEfoot"
140+ , "\\NC[align=left] 3.1"
141+ , "\\NC[align=right] 3.2"
142+ , "\\NC[align=middle] 3.3"
143+ , "\\NC 3.4"
144+ , "\\NC\\NR"
145+ , "\\stopTABLEfoot"
146+ , "\\stopTABLE"
147+ , "\\stopplacetable" ]
148+ ]
149+ ]
test/Tests/Writers/Docbook.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.Docbook (tests) where
34
5+import Prelude
46import Data.Text (unpack)
57import Test.Tasty
68import Tests.Helpers
test/Tests/Writers/Docbook.hs.orignew file+303
@@ -0,0 +1,303 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.Docbook (tests) where
3+
4+import Data.Text (unpack)
5+import Test.Tasty
6+import Tests.Helpers
7+import Text.Pandoc
8+import Text.Pandoc.Arbitrary ()
9+import Text.Pandoc.Builder
10+
11+docbook :: (ToPandoc a) => a -> String
12+docbook = docbookWithOpts def{ writerWrapText = WrapNone }
13+
14+docbookWithOpts :: ToPandoc a => WriterOptions -> a -> String
15+docbookWithOpts opts = unpack . purely (writeDocbook4 opts) . toPandoc
16+
17+{-
18+ "my test" =: X =?> Y
19+
20+is shorthand for
21+
22+ test docbook "my test" $ X =?> Y
23+
24+which is in turn shorthand for
25+
26+ test docbook "my test" (X,Y)
27+-}
28+
29+infix 4 =:
30+(=:) :: (ToString a, ToPandoc a)
31+ => String -> (a, String) -> TestTree
32+(=:) = test docbook
33+
34+lineblock :: Blocks
35+lineblock = para ("some text" <> linebreak <>
36+ "and more lines" <> linebreak <>
37+ "and again")
38+lineblock_out :: [String]
39+lineblock_out = [ "<literallayout>some text"
40+ , "and more lines"
41+ , "and again</literallayout>"
42+ ]
43+
44+tests :: [TestTree]
45+tests = [ testGroup "line blocks"
46+ [ "none" =: para "This is a test"
47+ =?> unlines
48+ [ "<para>"
49+ , " This is a test"
50+ , "</para>"
51+ ]
52+ , "basic" =: lineblock
53+ =?> unlines lineblock_out
54+ , "blockquote" =: blockQuote lineblock
55+ =?> unlines
56+ ( [ "<blockquote>" ] ++
57+ lineblock_out ++
58+ [ "</blockquote>" ]
59+ )
60+ , "footnote" =: para ("This is a test" <>
61+ note lineblock <>
62+ " of footnotes")
63+ =?> unlines
64+ ( [ "<para>"
65+ , " This is a test<footnote>" ] ++
66+ lineblock_out ++
67+ [ " </footnote> of footnotes"
68+ , "</para>" ]
69+ )
70+ ]
71+ , testGroup "compact lists"
72+ [ testGroup "bullet"
73+ [ "compact" =: bulletList [plain "a", plain "b", plain "c"]
74+ =?> unlines
75+ [ "<itemizedlist spacing=\"compact\">"
76+ , " <listitem>"
77+ , " <para>"
78+ , " a"
79+ , " </para>"
80+ , " </listitem>"
81+ , " <listitem>"
82+ , " <para>"
83+ , " b"
84+ , " </para>"
85+ , " </listitem>"
86+ , " <listitem>"
87+ , " <para>"
88+ , " c"
89+ , " </para>"
90+ , " </listitem>"
91+ , "</itemizedlist>"
92+ ]
93+ , "loose" =: bulletList [para "a", para "b", para "c"]
94+ =?> unlines
95+ [ "<itemizedlist>"
96+ , " <listitem>"
97+ , " <para>"
98+ , " a"
99+ , " </para>"
100+ , " </listitem>"
101+ , " <listitem>"
102+ , " <para>"
103+ , " b"
104+ , " </para>"
105+ , " </listitem>"
106+ , " <listitem>"
107+ , " <para>"
108+ , " c"
109+ , " </para>"
110+ , " </listitem>"
111+ , "</itemizedlist>"
112+ ]
113+ ]
114+ , testGroup "ordered"
115+ [ "compact" =: orderedList [plain "a", plain "b", plain "c"]
116+ =?> unlines
117+ [ "<orderedlist spacing=\"compact\">"
118+ , " <listitem>"
119+ , " <para>"
120+ , " a"
121+ , " </para>"
122+ , " </listitem>"
123+ , " <listitem>"
124+ , " <para>"
125+ , " b"
126+ , " </para>"
127+ , " </listitem>"
128+ , " <listitem>"
129+ , " <para>"
130+ , " c"
131+ , " </para>"
132+ , " </listitem>"
133+ , "</orderedlist>"
134+ ]
135+ , "loose" =: orderedList [para "a", para "b", para "c"]
136+ =?> unlines
137+ [ "<orderedlist>"
138+ , " <listitem>"
139+ , " <para>"
140+ , " a"
141+ , " </para>"
142+ , " </listitem>"
143+ , " <listitem>"
144+ , " <para>"
145+ , " b"
146+ , " </para>"
147+ , " </listitem>"
148+ , " <listitem>"
149+ , " <para>"
150+ , " c"
151+ , " </para>"
152+ , " </listitem>"
153+ , "</orderedlist>"
154+ ]
155+ ]
156+ , testGroup "definition"
157+ [ "compact" =: definitionList [ ("an", [plain "apple" ])
158+ , ("a", [plain "banana"])
159+ , ("an", [plain "orange"])]
160+ =?> unlines
161+ [ "<variablelist spacing=\"compact\">"
162+ , " <varlistentry>"
163+ , " <term>"
164+ , " an"
165+ , " </term>"
166+ , " <listitem>"
167+ , " <para>"
168+ , " apple"
169+ , " </para>"
170+ , " </listitem>"
171+ , " </varlistentry>"
172+ , " <varlistentry>"
173+ , " <term>"
174+ , " a"
175+ , " </term>"
176+ , " <listitem>"
177+ , " <para>"
178+ , " banana"
179+ , " </para>"
180+ , " </listitem>"
181+ , " </varlistentry>"
182+ , " <varlistentry>"
183+ , " <term>"
184+ , " an"
185+ , " </term>"
186+ , " <listitem>"
187+ , " <para>"
188+ , " orange"
189+ , " </para>"
190+ , " </listitem>"
191+ , " </varlistentry>"
192+ , "</variablelist>"
193+ ]
194+ , "loose" =: definitionList [ ("an", [para "apple" ])
195+ , ("a", [para "banana"])
196+ , ("an", [para "orange"])]
197+ =?> unlines
198+ [ "<variablelist>"
199+ , " <varlistentry>"
200+ , " <term>"
201+ , " an"
202+ , " </term>"
203+ , " <listitem>"
204+ , " <para>"
205+ , " apple"
206+ , " </para>"
207+ , " </listitem>"
208+ , " </varlistentry>"
209+ , " <varlistentry>"
210+ , " <term>"
211+ , " a"
212+ , " </term>"
213+ , " <listitem>"
214+ , " <para>"
215+ , " banana"
216+ , " </para>"
217+ , " </listitem>"
218+ , " </varlistentry>"
219+ , " <varlistentry>"
220+ , " <term>"
221+ , " an"
222+ , " </term>"
223+ , " <listitem>"
224+ , " <para>"
225+ , " orange"
226+ , " </para>"
227+ , " </listitem>"
228+ , " </varlistentry>"
229+ , "</variablelist>"
230+ ]
231+ ]
232+ ]
233+ , testGroup "writer options"
234+ [ testGroup "top-level division" $
235+ let
236+ headers = header 1 (text "header1")
237+ <> header 2 (text "header2")
238+ <> header 3 (text "header3")
239+
240+ docbookTopLevelDiv :: (ToPandoc a)
241+ => TopLevelDivision -> a -> String
242+ docbookTopLevelDiv division =
243+ docbookWithOpts def{ writerTopLevelDivision = division }
244+ in
245+ [ test (docbookTopLevelDiv TopLevelSection) "sections as top-level" $
246+ headers =?>
247+ unlines [ "<sect1>"
248+ , " <title>header1</title>"
249+ , " <sect2>"
250+ , " <title>header2</title>"
251+ , " <sect3>"
252+ , " <title>header3</title>"
253+ , " <para>"
254+ , " </para>"
255+ , " </sect3>"
256+ , " </sect2>"
257+ , "</sect1>"
258+ ]
259+ , test (docbookTopLevelDiv TopLevelChapter) "chapters as top-level" $
260+ headers =?>
261+ unlines [ "<chapter>"
262+ , " <title>header1</title>"
263+ , " <sect1>"
264+ , " <title>header2</title>"
265+ , " <sect2>"
266+ , " <title>header3</title>"
267+ , " <para>"
268+ , " </para>"
269+ , " </sect2>"
270+ , " </sect1>"
271+ , "</chapter>"
272+ ]
273+ , test (docbookTopLevelDiv TopLevelPart) "parts as top-level" $
274+ headers =?>
275+ unlines [ "<part>"
276+ , " <title>header1</title>"
277+ , " <chapter>"
278+ , " <title>header2</title>"
279+ , " <sect1>"
280+ , " <title>header3</title>"
281+ , " <para>"
282+ , " </para>"
283+ , " </sect1>"
284+ , " </chapter>"
285+ , "</part>"
286+ ]
287+ , test (docbookTopLevelDiv TopLevelDefault) "default top-level" $
288+ headers =?>
289+ unlines [ "<sect1>"
290+ , " <title>header1</title>"
291+ , " <sect2>"
292+ , " <title>header2</title>"
293+ , " <sect3>"
294+ , " <title>header3</title>"
295+ , " <para>"
296+ , " </para>"
297+ , " </sect3>"
298+ , " </sect2>"
299+ , "</sect1>"
300+ ]
301+ ]
302+ ]
303+ ]
test/Tests/Writers/Docx.hs+2
@@ -1,5 +1,7 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12module Tests.Writers.Docx (tests) where
23
4+import Prelude
35import Text.Pandoc
46import Test.Tasty
57import Tests.Writers.OOXML
test/Tests/Writers/Docx.hs.orignew file+157
@@ -0,0 +1,157 @@
1+module Tests.Writers.Docx (tests) where
2+
3+import Text.Pandoc
4+import Test.Tasty
5+import Tests.Writers.OOXML
6+import Test.Tasty.HUnit
7+import Data.List (isPrefixOf)
8+
9+-- we add an extra check to make sure that we're not writing in the
10+-- toplevel docx directory. We don't want to accidentally overwrite an
11+-- Word-generated docx file used to test the reader.
12+docxTest :: String -> WriterOptions -> FilePath -> FilePath -> TestTree
13+docxTest testName opts nativeFP goldenFP =
14+ if "docx/golden/" `isPrefixOf` goldenFP
15+ then ooxmlTest writeDocx testName opts nativeFP goldenFP
16+ else testCase testName $
17+ assertFailure $
18+ goldenFP ++ " is not in `test/docx/golden`"
19+
20+tests :: [TestTree]
21+tests = [ testGroup "inlines"
22+ [ docxTest
23+ "font formatting"
24+ def
25+ "docx/inline_formatting.native"
26+ "docx/golden/inline_formatting.docx"
27+ , docxTest
28+ "hyperlinks"
29+ def
30+ "docx/links.native"
31+ "docx/golden/links.docx"
32+ , docxTest
33+ "inline image"
34+ def
35+ "docx/image_writer_test.native"
36+ "docx/golden/image.docx"
37+ , docxTest
38+ "inline images"
39+ def
40+ "docx/inline_images_writer_test.native"
41+ "docx/golden/inline_images.docx"
42+ , docxTest
43+ "handling unicode input"
44+ def
45+ "docx/unicode.native"
46+ "docx/golden/unicode.docx"
47+ , docxTest
48+ "inline code"
49+ def
50+ "docx/inline_code.native"
51+ "docx/golden/inline_code.docx"
52+ , docxTest
53+ "inline code in subscript and superscript"
54+ def
55+ "docx/verbatim_subsuper.native"
56+ "docx/golden/verbatim_subsuper.docx"
57+ ]
58+ , testGroup "blocks"
59+ [ docxTest
60+ "headers"
61+ def
62+ "docx/headers.native"
63+ "docx/golden/headers.docx"
64+ , docxTest
65+ "nested anchor spans in header"
66+ def
67+ "docx/nested_anchors_in_header.native"
68+ "docx/golden/nested_anchors_in_header.docx"
69+ , docxTest
70+ "lists"
71+ def
72+ "docx/lists.native"
73+ "docx/golden/lists.docx"
74+ , docxTest
75+ "lists continuing after interruption"
76+ def
77+ "docx/lists_continuing.native"
78+ "docx/golden/lists_continuing.docx"
79+ , docxTest
80+ "lists restarting after interruption"
81+ def
82+ "docx/lists_restarting.native"
83+ "docx/golden/lists_restarting.docx"
84+ , docxTest
85+ "definition lists"
86+ def
87+ "docx/definition_list.native"
88+ "docx/golden/definition_list.docx"
89+ , docxTest
90+ "footnotes and endnotes"
91+ def
92+ "docx/notes.native"
93+ "docx/golden/notes.docx"
94+ , docxTest
95+ "links in footnotes and endnotes"
96+ def
97+ "docx/link_in_notes.native"
98+ "docx/golden/link_in_notes.docx"
99+ , docxTest
100+ "blockquotes"
101+ def
102+ "docx/block_quotes_parse_indent.native"
103+ "docx/golden/block_quotes.docx"
104+ , docxTest
105+ "tables"
106+ def
107+ "docx/tables.native"
108+ "docx/golden/tables.docx"
109+ , docxTest
110+ "tables with lists in cells"
111+ def
112+ "docx/table_with_list_cell.native"
113+ "docx/golden/table_with_list_cell.docx"
114+ , docxTest
115+ "tables with one row"
116+ def
117+ "docx/table_one_row.native"
118+ "docx/golden/table_one_row.docx"
119+ , docxTest
120+ "code block"
121+ def
122+ "docx/codeblock.native"
123+ "docx/golden/codeblock.docx"
124+ ]
125+ , testGroup "track changes"
126+ [ docxTest
127+ "insertion"
128+ def
129+ "docx/track_changes_insertion_all.native"
130+ "docx/golden/track_changes_insertion.docx"
131+ , docxTest
132+ "deletion"
133+ def
134+ "docx/track_changes_deletion_all.native"
135+ "docx/golden/track_changes_deletion.docx"
136+ , docxTest
137+ "move text"
138+ def
139+ "docx/track_changes_move_all.native"
140+ "docx/golden/track_changes_move.docx"
141+ , docxTest
142+ "comments"
143+ def
144+ "docx/comments.native"
145+ "docx/golden/comments.docx"
146+ ]
147+ , testGroup "custom styles"
148+ [ docxTest "custom styles without reference.docx"
149+ def
150+ "docx/custom_style.native"
151+ "docx/golden/custom_style_no_reference.docx"
152+ , docxTest "custom styles with reference.docx"
153+ def{writerReferenceDoc = Just "docx/custom-style-reference.docx"}
154+ "docx/custom_style.native"
155+ "docx/golden/custom_style_reference.docx"
156+ ]
157+ ]
test/Tests/Writers/FB2.hs+4−2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.FB2 (tests) where
34
5+import Prelude
46import Test.Tasty
57import Tests.Helpers
68import Text.Pandoc
@@ -23,8 +25,8 @@ tests = [ testGroup "block elements"
2325 ]
2426 , testGroup "inlines"
2527 [
26− "Emphasis" =: emph "emphasized"
27− =?> fb2 "<emphasis>emphasized</emphasis>"
28+ "Emphasis" =: para (emph "emphasized")
29+ =?> fb2 "<p><emphasis>emphasized</emphasis></p>"
2830 ]
2931 , "bullet list" =: bulletList [ plain $ text "first"
3032 , plain $ text "second"
test/Tests/Writers/FB2.hs.orignew file+34
@@ -0,0 +1,34 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.FB2 (tests) where
3+
4+import Test.Tasty
5+import Tests.Helpers
6+import Text.Pandoc
7+import Text.Pandoc.Arbitrary ()
8+import Text.Pandoc.Builder
9+
10+fb2 :: String -> String
11+fb2 x = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" ++
12+ "<FictionBook xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\" xmlns:l=\"http://www.w3.org/1999/xlink\"><description><title-info><genre>unrecognised</genre></title-info><document-info><program-used>pandoc</program-used></document-info></description><body><title><p /></title><section>" ++ x ++ "</section></body></FictionBook>"
13+
14+infix 4 =:
15+(=:) :: (ToString a, ToPandoc a)
16+ => String -> (a, String) -> TestTree
17+(=:) = test (purely (writeFB2 def) . toPandoc)
18+
19+tests :: [TestTree]
20+tests = [ testGroup "block elements"
21+ ["para" =: para "Lorem ipsum cetera."
22+ =?> fb2 "<p>Lorem ipsum cetera.</p>"
23+ ]
24+ , testGroup "inlines"
25+ [
26+ "Emphasis" =: emph "emphasized"
27+ =?> fb2 "<emphasis>emphasized</emphasis>"
28+ ]
29+ , "bullet list" =: bulletList [ plain $ text "first"
30+ , plain $ text "second"
31+ , plain $ text "third"
32+ ]
33+ =?> fb2 "<p>\x2022 first</p><p>\x2022 second</p><p>\x2022 third</p>"
34+ ]
test/Tests/Writers/HTML.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.HTML (tests) where
34
5+import Prelude
46import Data.Text (unpack)
57import Test.Tasty
68import Tests.Helpers
test/Tests/Writers/HTML.hs.orignew file+44
@@ -0,0 +1,44 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.HTML (tests) where
3+
4+import Data.Text (unpack)
5+import Test.Tasty
6+import Tests.Helpers
7+import Text.Pandoc
8+import Text.Pandoc.Arbitrary ()
9+import Text.Pandoc.Builder
10+
11+html :: (ToPandoc a) => a -> String
12+html = unpack . purely (writeHtml4String def{ writerWrapText = WrapNone }) . toPandoc
13+
14+{-
15+ "my test" =: X =?> Y
16+
17+is shorthand for
18+
19+ test html "my test" $ X =?> Y
20+
21+which is in turn shorthand for
22+
23+ test html "my test" (X,Y)
24+-}
25+
26+infix 4 =:
27+(=:) :: (ToString a, ToPandoc a)
28+ => String -> (a, String) -> TestTree
29+(=:) = test html
30+
31+tests :: [TestTree]
32+tests = [ testGroup "inline code"
33+ [ "basic" =: code "@&" =?> "<code>@&amp;</code>"
34+ , "haskell" =: codeWith ("",["haskell"],[]) ">>="
35+ =?> "<code class=\"sourceCode haskell\"><span class=\"fu\">&gt;&gt;=</span></code>"
36+ , "nolanguage" =: codeWith ("",["nolanguage"],[]) ">>="
37+ =?> "<code class=\"nolanguage\">&gt;&gt;=</code>"
38+ ]
39+ , testGroup "images"
40+ [ "alt with formatting" =:
41+ image "/url" "title" ("my " <> emph "image")
42+ =?> "<img src=\"/url\" title=\"title\" alt=\"my image\" />"
43+ ]
44+ ]
test/Tests/Writers/JATS.hs+14−26
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.JATS (tests) where
34
5+import Prelude
46import Data.Text (unpack)
57import Test.Tasty
68import Tests.Helpers
@@ -30,8 +32,8 @@ infix 4 =:
3032
3133tests :: [TestTree]
3234tests = [ testGroup "inline code"
33− [ "basic" =: code "@&" =?> "<p>\n <monospace>@&amp;</monospace>\n</p>"
34− , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p>\n <code language=\"c\">@&amp;</code>\n</p>"
35+ [ "basic" =: code "@&" =?> "<p><monospace>@&amp;</monospace></p>"
36+ , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p><code language=\"c\">@&amp;</code></p>"
3537 ]
3638 , testGroup "block code"
3739 [ "basic" =: codeBlock "@&" =?> "<preformat>@&amp;</preformat>"
@@ -44,7 +46,7 @@ tests = [ testGroup "inline code"
4446 ]
4547 , testGroup "inlines"
4648 [ "Emphasis" =: emph "emphasized"
47− =?> "<p>\n <italic>emphasized</italic>\n</p>"
49+ =?> "<p><italic>emphasized</italic></p>"
4850 ]
4951 , "bullet list" =: bulletList [ plain $ text "first"
5052 , plain $ text "second"
@@ -52,19 +54,13 @@ tests = [ testGroup "inline code"
5254 ]
5355 =?> "<list list-type=\"bullet\">\n\
5456 \ <list-item>\n\
55− \ <p>\n\
56− \ first\n\
57− \ </p>\n\
57+ \ <p>first</p>\n\
5858 \ </list-item>\n\
5959 \ <list-item>\n\
60− \ <p>\n\
61− \ second\n\
62− \ </p>\n\
60+ \ <p>second</p>\n\
6361 \ </list-item>\n\
6462 \ <list-item>\n\
65− \ <p>\n\
66− \ third\n\
67− \ </p>\n\
63+ \ <p>third</p>\n\
6864 \ </list-item>\n\
6965 \</list>"
7066 , testGroup "definition lists"
@@ -72,24 +68,18 @@ tests = [ testGroup "inline code"
7268 [plain (text "hi there")])] =?>
7369 "<def-list>\n\
7470 \ <def-item>\n\
75− \ <term>\n\
76− \ <xref alt=\"testing\" rid=\"go\">testing</xref>\n\
77− \ </term>\n\
71+ \ <term><xref alt=\"testing\" rid=\"go\">testing</xref></term>\n\
7872 \ <def>\n\
79− \ <p>\n\
80− \ hi there\n\
81− \ </p>\n\
73+ \ <p>hi there</p>\n\
8274 \ </def>\n\
8375 \ </def-item>\n\
8476 \</def-list>"
8577 ]
8678 , testGroup "math"
8779 [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
88− "<p>\n\
89− \ <inline-formula><alternatives>\n\
90− \ <tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
91− \ <mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula>\n\
92− \</p>"
80+ "<p><inline-formula><alternatives>\n\
81+ \<tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
82+ \<mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula></p>"
9383 ]
9484 , testGroup "headers"
9585 [ "unnumbered header" =:
@@ -97,9 +87,7 @@ tests = [ testGroup "inline code"
9787 (text "Header 1" <> note (plain $ text "note")) =?>
9888 "<sec id=\"foo\">\n\
9989 \ <title>Header 1<fn>\n\
100− \ <p>\n\
101− \ note\n\
102− \ </p>\n\
90+ \ <p>note</p>\n\
10391 \ </fn></title>\n\
10492 \</sec>"
10593 , "unnumbered sub header" =:
test/Tests/Writers/JATS.hs.orignew file+108
@@ -0,0 +1,108 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Tests.Writers.JATS (tests) where
3+
4+import Data.Text (unpack)
5+import Test.Tasty
6+import Tests.Helpers
7+import Text.Pandoc
8+import Text.Pandoc.Arbitrary ()
9+import Text.Pandoc.Builder
10+
11+jats :: (ToPandoc a) => a -> String
12+jats = unpack . purely (writeJATS def{ writerWrapText = WrapNone }) . toPandoc
13+
14+{-
15+ "my test" =: X =?> Y
16+
17+is shorthand for
18+
19+ test jats "my test" $ X =?> Y
20+
21+which is in turn shorthand for
22+
23+ test jats "my test" (X,Y)
24+-}
25+
26+infix 4 =:
27+(=:) :: (ToString a, ToPandoc a)
28+ => String -> (a, String) -> TestTree
29+(=:) = test jats
30+
31+tests :: [TestTree]
32+tests = [ testGroup "inline code"
33+ [ "basic" =: code "@&" =?> "<p><monospace>@&amp;</monospace></p>"
34+ , "lang" =: codeWith ("", ["c"], []) "@&" =?> "<p><code language=\"c\">@&amp;</code></p>"
35+ ]
36+ , testGroup "block code"
37+ [ "basic" =: codeBlock "@&" =?> "<preformat>@&amp;</preformat>"
38+ , "lang" =: codeBlockWith ("", ["c"], []) "@&" =?> "<code language=\"c\">@&amp;</code>"
39+ ]
40+ , testGroup "images"
41+ [ "basic" =:
42+ image "/url" "title" mempty
43+ =?> "<graphic mimetype=\"image\" mime-subtype=\"\" xlink:href=\"/url\" xlink:title=\"title\" />"
44+ ]
45+ , testGroup "inlines"
46+ [ "Emphasis" =: emph "emphasized"
47+ =?> "<p><italic>emphasized</italic></p>"
48+ ]
49+ , "bullet list" =: bulletList [ plain $ text "first"
50+ , plain $ text "second"
51+ , plain $ text "third"
52+ ]
53+ =?> "<list list-type=\"bullet\">\n\
54+ \ <list-item>\n\
55+ \ <p>first</p>\n\
56+ \ </list-item>\n\
57+ \ <list-item>\n\
58+ \ <p>second</p>\n\
59+ \ </list-item>\n\
60+ \ <list-item>\n\
61+ \ <p>third</p>\n\
62+ \ </list-item>\n\
63+ \</list>"
64+ , testGroup "definition lists"
65+ [ "with internal link" =: definitionList [(link "#go" "" (str "testing"),
66+ [plain (text "hi there")])] =?>
67+ "<def-list>\n\
68+ \ <def-item>\n\
69+ \ <term><xref alt=\"testing\" rid=\"go\">testing</xref></term>\n\
70+ \ <def>\n\
71+ \ <p>hi there</p>\n\
72+ \ </def>\n\
73+ \ </def-item>\n\
74+ \</def-list>"
75+ ]
76+ , testGroup "math"
77+ [ "escape |" =: para (math "\\sigma|_{\\{x\\}}") =?>
78+ "<p><inline-formula><alternatives>\n\
79+ \<tex-math><![CDATA[\\sigma|_{\\{x\\}}]]></tex-math>\n\
80+ \<mml:math display=\"inline\" xmlns:mml=\"http://www.w3.org/1998/Math/MathML\"><mml:mrow><mml:mi>σ</mml:mi><mml:msub><mml:mo stretchy=\"false\" form=\"prefix\">|</mml:mo><mml:mrow><mml:mo stretchy=\"false\" form=\"prefix\">{</mml:mo><mml:mi>x</mml:mi><mml:mo stretchy=\"false\" form=\"postfix\">}</mml:mo></mml:mrow></mml:msub></mml:mrow></mml:math></alternatives></inline-formula></p>"
81+ ]
82+ , testGroup "headers"
83+ [ "unnumbered header" =:
84+ headerWith ("foo",["unnumbered"],[]) 1
85+ (text "Header 1" <> note (plain $ text "note")) =?>
86+ "<sec id=\"foo\">\n\
87+ \ <title>Header 1<fn>\n\
88+ \ <p>note</p>\n\
89+ \ </fn></title>\n\
90+ \</sec>"
91+ , "unnumbered sub header" =:
92+ headerWith ("foo",["unnumbered"],[]) 1
93+ (text "Header")
94+ <> headerWith ("foo",["unnumbered"],[]) 2
95+ (text "Sub-Header") =?>
96+ "<sec id=\"foo\">\n\
97+ \ <title>Header</title>\n\
98+ \ <sec id=\"foo\">\n\
99+ \ <title>Sub-Header</title>\n\
100+ \ </sec>\n\
101+ \</sec>"
102+ , "containing image" =:
103+ header 1 (image "imgs/foo.jpg" "" (text "Alt text")) =?>
104+ "<sec>\n\
105+ \ <title><inline-graphic mimetype=\"image\" mime-subtype=\"jpeg\" xlink:href=\"imgs/foo.jpg\" /></title>\n\
106+ \</sec>"
107+ ]
108+ ]
test/Tests/Writers/LaTeX.hs+2
@@ -1,6 +1,8 @@
1+{-# LANGUAGE NoImplicitPrelude #-}
12{-# LANGUAGE OverloadedStrings #-}
23module Tests.Writers.LaTeX (tests) where
34
5+import Prelude
46import Data.Text (unpack)
57import Test.Tasty
68import Tests.Helpers
test/Tests/Writers/LaTeX.hs.orignew file+176

This diff is too big to show here.

test/Tests/Writers/Markdown.hs+2

This diff is too big to show here.

test/Tests/Writers/Markdown.hs.orignew file+267

This diff is too big to show here.

test/Tests/Writers/Muse.hs+117−26

This diff is too big to show here.

test/Tests/Writers/Muse.hs.orignew file+410

This diff is too big to show here.

test/Tests/Writers/Native.hs+2

This diff is too big to show here.

test/Tests/Writers/Native.hs.orignew file+22

This diff is too big to show here.

test/Tests/Writers/OOXML.hs+2−2

This diff is too big to show here.

test/Tests/Writers/OOXML.hs.orignew file+184

This diff is too big to show here.

test/Tests/Writers/Org.hs+2

This diff is too big to show here.

test/Tests/Writers/Org.hs.orignew file+25

This diff is too big to show here.

test/Tests/Writers/Plain.hs+2

This diff is too big to show here.

test/Tests/Writers/Plain.hs.orignew file+21

This diff is too big to show here.

test/Tests/Writers/Powerpoint.hs+19

This diff is too big to show here.

test/Tests/Writers/Powerpoint.hs.orignew file+93

This diff is too big to show here.

test/Tests/Writers/RST.hs+51−9

This diff is too big to show here.

test/Tests/Writers/RST.hs.orignew file+130

This diff is too big to show here.

test/Tests/Writers/TEI.hs+2

This diff is too big to show here.

test/Tests/Writers/TEI.hs.orignew file+43

This diff is too big to show here.

test/command/1710.md+2−3

This diff is too big to show here.

test/command/2649.md+11−9

This diff is too big to show here.

test/command/3348.md+1−1

This diff is too big to show here.

test/command/3510-src.hs.orignew file+1

This diff is too big to show here.

test/command/3587.md+36

This diff is too big to show here.

test/command/3675.md+2−2

This diff is too big to show here.

test/command/4016.md+2−3

This diff is too big to show here.

test/command/4320.mdnew file+15

This diff is too big to show here.

test/command/4424.mdnew file+10

This diff is too big to show here.

test/command/4454.mdnew file+9

This diff is too big to show here.

test/command/4513.mdnew file+9

This diff is too big to show here.

test/command/4527.mdnew file+21

This diff is too big to show here.

test/command/4529.mdnew file+36

This diff is too big to show here.

test/command/4550.mdnew file+7

This diff is too big to show here.

test/command/4576.mdnew file+6

This diff is too big to show here.

test/command/4578.mdnew file+14

This diff is too big to show here.

test/command/4579.mdnew file+16

This diff is too big to show here.

test/command/4589.mdnew file+14

This diff is too big to show here.

test/command/4594.mdnew file+24

This diff is too big to show here.

test/command/4598.mdnew file+10

This diff is too big to show here.

test/command/sloppypar.mdnew file+23

This diff is too big to show here.

test/docx/adjacent_codeblocks.docxnew file

Binary file not shown.

test/docx/adjacent_codeblocks.nativenew file+6

This diff is too big to show here.

test/docx/block_quotes.docx

Binary file not shown.

test/docx/char_styles.docx

Binary file not shown.

test/docx/custom-style-with-styles.native+1−1

This diff is too big to show here.

test/docx/deep_normalize.docx

Binary file not shown.

test/docx/drop_cap.docx

Binary file not shown.

test/docx/golden/image.docx

Binary file not shown.

test/docx/golden/inline_formatting.docx

Binary file not shown.

test/docx/golden/inline_images.docx

Binary file not shown.

test/docx/hanging_indent.docx

Binary file not shown.

test/docx/headers.docx

Binary file not shown.

test/docx/image_writer_test.native+8−5

This diff is too big to show here.

test/docx/inline_formatting.docx

Binary file not shown.

test/docx/inline_images.docx

Binary file not shown.

test/docx/link_in_notes.docx

Binary file not shown.

test/docx/links.docx

Binary file not shown.

test/docx/lists.docx

Binary file not shown.

test/docx/metadata.docx

Binary file not shown.

test/docx/metadata_after_normal.docx

Binary file not shown.

test/docx/nested_sdt.docxnew file

Binary file not shown.

test/docx/nested_sdt.nativenew file+3

This diff is too big to show here.

test/docx/nested_smart_tags.docxnew file

Binary file not shown.

test/docx/nested_smart_tags.nativenew file+7

This diff is too big to show here.

test/docx/normalize.docx

Binary file not shown.

test/docx/notes.docx

Binary file not shown.

test/docx/numbered_header.docx

Binary file not shown.

test/docx/table_variable_width.native+3

This diff is too big to show here.

test/docx/table_with_list_cell.docx

Binary file not shown.

test/docx/tables.docx

Binary file not shown.

test/dokuwiki_multiblock_table.dokuwiki+4−3

This diff is too big to show here.

test/dokuwiki_multiblock_table.native+6−1

This diff is too big to show here.

test/fb2/basic.fb2+74−2

This diff is too big to show here.

test/fb2/meta.fb2new file+3

This diff is too big to show here.

test/fb2/meta.markdownnew file+7

This diff is too big to show here.

test/fb2/reader/emphasis.fb2new file+11

This diff is too big to show here.

test/fb2/reader/emphasis.nativenew file+6

This diff is too big to show here.

test/fb2/reader/epigraph.fb2new file+18

This diff is too big to show here.

test/fb2/reader/epigraph.nativenew file+9

This diff is too big to show here.

test/fb2/reader/meta.fb2new file+26

This diff is too big to show here.

test/fb2/reader/meta.nativenew file+2

This diff is too big to show here.

test/fb2/reader/poem.fb2new file+28

This diff is too big to show here.

test/fb2/reader/poem.nativenew file+14

This diff is too big to show here.

test/fb2/reader/titles.fb2new file+18

This diff is too big to show here.

test/fb2/reader/titles.nativenew file+8

This diff is too big to show here.

test/fb2/titles.fb2+1−1

This diff is too big to show here.

test/fb2/titles.markdown+1−1

This diff is too big to show here.

test/jats-reader.native+2−2

This diff is too big to show here.

test/jats-reader.xml+352−977

This diff is too big to show here.

test/lhs-test.rst+5−5

This diff is too big to show here.

test/lhs-test.rst+lhs+2−2

This diff is too big to show here.

test/lua/math.luanew file+10

This diff is too big to show here.

test/lua/script-name.luanew file+3

This diff is too big to show here.

test/lua/test-pandoc-utils.lua+21−13

This diff is too big to show here.

test/pandoc-test14632-86new file+1448

This diff is too big to show here.

test/pandoc-test14632-89new file

No changes to the content.

test/pandoc-test14632-90new file

No changes to the content.

test/pandoc-test14632-91new file

No changes to the content.

test/pandoc-test14632-94new file

No changes to the content.

test/pandoc-test14632-95new file

No changes to the content.

test/pandoc-test14632-96new file

No changes to the content.

test/pandoc-test14632-97new file

No changes to the content.

test/pandoc-test77993-78new file

No changes to the content.

test/pandoc-test77993-79new file

No changes to the content.

test/pandoc-test77993-82new file

No changes to the content.

test/pandoc-test77993-83new file

No changes to the content.

test/pandoc-test77993-86new file

No changes to the content.

test/pandoc-test77993-87new file

No changes to the content.

test/pandoc-test77993-90new file

No changes to the content.

test/pandoc-test77993-91new file

No changes to the content.

test/pandoc-test88473-110new file

No changes to the content.

test/pandoc-test88473-111new file

No changes to the content.

test/pandoc-test88473-112new file

No changes to the content.

test/pandoc-test88473-113new file

No changes to the content.

test/pandoc-test88473-116new file

No changes to the content.

test/pandoc-test88473-117new file

No changes to the content.

test/pandoc-test88473-118new file

No changes to the content.

test/pandoc-test88473-119new file

No changes to the content.

test/pandoc-test94017-86new file

No changes to the content.

test/pandoc-test94017-87new file

No changes to the content.

test/pandoc-test94017-90new file

No changes to the content.

test/pandoc-test94017-91new file

No changes to the content.

test/pandoc-test94017-92new file

No changes to the content.

test/pandoc-test94017-93new file

No changes to the content.

test/pptx/endnotes_templated.pptx

Binary file not shown.

test/pptx/endnotes_toc_templated.pptx

Binary file not shown.

test/pptx/images_templated.pptx

Binary file not shown.

test/pptx/lists.nativenew file+18

This diff is too big to show here.

test/pptx/lists.pptxnew file

Binary file not shown.

test/pptx/lists_templated.pptxnew file

Binary file not shown.

test/pptx/remove_empty_slides.nativenew file+5

This diff is too big to show here.

test/pptx/remove_empty_slides.pptxnew file

Binary file not shown.

test/pptx/remove_empty_slides_templated.pptxnew file

Binary file not shown.

test/pptx/slide_breaks_slide_level_1_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_templated.pptx

Binary file not shown.

test/pptx/slide_breaks_toc_templated.pptx

Binary file not shown.

test/pptx/speaker_notes_afterseps.nativenew file+33

This diff is too big to show here.

test/pptx/speaker_notes_afterseps.pptxnew file

Binary file not shown.

test/pptx/speaker_notes_afterseps_templated.pptxnew file

Binary file not shown.

test/pptx/tables.nativenew file+35

This diff is too big to show here.

test/pptx/tables.pptxnew file

Binary file not shown.

test/pptx/tables_templated.pptxnew file

Binary file not shown.

test/s5-fancy.html+2−202

This diff is too big to show here.

test/tables-rstsubset.native+6−6

This diff is too big to show here.

test/tables.asciidoc+3−3

This diff is too big to show here.

test/tables.context+8−8

This diff is too big to show here.

test/tables.custom+3−3

This diff is too big to show here.

test/tables.docbook4+3−3

This diff is too big to show here.

test/tables.docbook5+3−3

This diff is too big to show here.

test/tables.fb2+14−1

This diff is too big to show here.

test/tables.haddock+67−53

This diff is too big to show here.

test/tables.html4+6−6

This diff is too big to show here.

test/tables.html5+6−6

This diff is too big to show here.

test/tables.icml+3−3

This diff is too big to show here.

test/tables.jats+105−309

This diff is too big to show here.

test/tables.latex+9−9

This diff is too big to show here.

test/tables.man+3−3

This diff is too big to show here.

test/tables.markdown+8−8

This diff is too big to show here.

test/tables.mediawiki+3−3

This diff is too big to show here.

test/tables.ms+7−7

This diff is too big to show here.

test/tables.native+3−3

This diff is too big to show here.

test/tables.plain+8−8

This diff is too big to show here.

test/tables.rst+30−30

This diff is too big to show here.

test/tables.rtf+8−8

This diff is too big to show here.

test/tables.texinfo+3−3

This diff is too big to show here.

test/tables.textile+3−3

This diff is too big to show here.

test/test-pandoc.hs+4

This diff is too big to show here.

test/test-pandoc.hs.orignew file+83

This diff is too big to show here.

test/writer.context+1−1

This diff is too big to show here.

test/writer.fb2+114−362

This diff is too big to show here.

test/writer.jats+357−923

This diff is too big to show here.

test/writer.ms+54−51

This diff is too big to show here.

test/writer.muse+13−13

This diff is too big to show here.

test/writer.rst+67−67

This diff is too big to show here.

test/writers-lang-and-dir.context+1−1

This diff is too big to show here.

test/writers-lang-and-dir.latex+2−2

This diff is too big to show here.

tools/update-readme.lua+16−32

This diff is too big to show here.

trypandoc/trypandoc.hs+2

This diff is too big to show here.